Skip to content

feat: exporter toolkit bootstrap#394

Open
nicolastakashi wants to merge 2 commits into
prometheus:masterfrom
nicolastakashi:bootstrap-runner
Open

feat: exporter toolkit bootstrap#394
nicolastakashi wants to merge 2 commits into
prometheus:masterfrom
nicolastakashi:bootstrap-runner

Conversation

@nicolastakashi
Copy link
Copy Markdown

@nicolastakashi nicolastakashi commented May 21, 2026

Summary

This adds a new optional bootstrap package to exporter-toolkit for exporters that want a shared startup path for common process wiring. Today, many exporters duplicate the same startup concerns around:

  • common web flags
  • logger setup
  • metrics path registration
  • landing page wiring
  • web.ListenAndServe integration

This PR introduces an additive package that can own those shared pieces without changing the existing web package API or forcing any current exporter to migrate.

Why

The goal is to reduce repeated startup code across exporters while keeping boundaries clear:

  • web remains focused on transport/server concerns such as listeners, TLS, auth, and serving
  • bootstrap owns higher-level exporter startup concerns such as flag registration, logging initialization, metrics endpoint wiring, and landing page setup

This is intentionally additive:

  • exporters already using web.ListenAndServe can continue unchanged
  • exporters can opt into bootstrap only if it simplifies their startup path
  • this gives us a concrete shared layer for downstream adoption without requiring ecosystem-wide churn

A key design choice in this PR is keeping web.telemetry-path ownership in bootstrap, not in web.FlagConfig, so transport concerns and exporter routing concerns do not get mixed together. It also keeps the existing web startup path intact.

Startup Example

Without bootstrap:

metricsPath := kingpin.Flag(
	"web.telemetry-path",
	"Path under which to expose metrics.",
).Default("/metrics").String()
disableExporterMetrics := kingpin.Flag(
	"web.disable-exporter-metrics",
	"Exclude metrics about the exporter itself (promhttp_*, process_*, go_*).",
).Bool()
maxRequests := kingpin.Flag(
	"web.max-requests",
	"Maximum number of parallel scrape requests. Use 0 to disable.",
).Default("40").Int()
toolkitFlags := kingpinflag.AddFlags(kingpin.CommandLine, ":9100")
promslogConfig := &promslog.Config{}
flag.AddFlags(kingpin.CommandLine, promslogConfig)
kingpin.Parse()
logger := promslog.New(promslogConfig)

http.Handle(*metricsPath, newHandler(!*disableExporterMetrics, *maxRequests, logger))
if *metricsPath != "/" {
	landingPage, err := web.NewLandingPage(web.LandingConfig{
		Name:        "My Exporter",
		Description: "Prometheus My Exporter",
		Version:     version.Info(),
		Links: []web.LandingLinks{{
			Address: *metricsPath,
			Text:    "Metrics",
		}},
	})
	if err != nil {
		level.Error(logger).Log("err", err)
		os.Exit(1)
	}
	http.Handle("/", landingPage)
}

server := &http.Server{}
if err := web.ListenAndServe(server, toolkitFlags, logger); err != nil {
	level.Error(logger).Log("err", err)
	os.Exit(1)
}

With bootstrap:

runner := bootstrap.New(bootstrap.Config{
	App:            kingpin.CommandLine,
	Name:           "my_exporter",
	Description:    "Prometheus My Exporter",
	DefaultAddress: ":9100",
	MetricsHandlerFactory: func(b *bootstrap.Bootstrap) (http.Handler, error) {
		return newHandler(!b.DisableExporterMetrics, b.MaxRequests, b.Logger), nil
	},
})
if err := runner.Run(); err != nil {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

Notes

  • This PR does not deprecate or remove the existing web startup flow.
  • This PR does not try to model exporter-specific runtime config.
  • This PR is intended to be proven by real downstream adoption, starting with node_exporter.

Signed-off-by: Nicolas Takashi <nicolas.tcs@hotmail.com>
@nicolastakashi nicolastakashi changed the title Exporter Toolkit Bootstrap feat: exporter toolkit bootstrap May 21, 2026
@SuperQ SuperQ requested a review from roidelapluie May 21, 2026 13:38
@SuperQ
Copy link
Copy Markdown
Member

SuperQ commented May 21, 2026

I think this is a continuation of #147

@nicolastakashi
Copy link
Copy Markdown
Author

I think this is a continuation of #147

Should we get the first one merged first @SuperQ ?

Copy link
Copy Markdown
Member

@ArthurSens ArthurSens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really cool! This can be so easily applied to a lot of exporters :)

Comment thread web/tls_config.go Outdated
Comment thread bootstrap/bootstrap.go Outdated
Comment thread bootstrap/bootstrap.go Outdated
Comment thread bootstrap/bootstrap.go Outdated
Comment thread bootstrap/bootstrap.go
Comment thread bootstrap/bootstrap.go Outdated
Comment thread bootstrap/bootstrap.go Outdated
Signed-off-by: Nicolas Takashi <nicolas.tcs@hotmail.com>
Copy link
Copy Markdown
Member

@ArthurSens ArthurSens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but let's see what exporter-toolkit maintainers have to say :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants