Added missing OpenTelemetry instrumentation to several API endpoints. (#32960)

Fixes #32331 

Manually tested all paths. `/test` path removed in
https://github.com/fleetdm/fleet/pull/32962

Also added support for sending errors to OpenTelemetry, like we do for
APM/Sentry.

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing
- [x] QA'd all new/changed functionality manually


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added OpenTelemetry tracing across core HTTP endpoints (health,
version, assets, metrics, enroll/root, debug, Apple MDM, SCEP, SCIM)
with dynamic per-request route instrumentation.
* Enhanced error reporting to include OpenTelemetry spans/events with
contextual user/host attributes.

* **Tests**
* Added unit tests validating SCIM and error-handling telemetry, span
naming, and sensitive-data redaction.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Victor Lyuboslavsky
2025-09-16 11:10:33 -05:00
committed by GitHub
parent 072bba770e
commit f522611f21
10 changed files with 572 additions and 34 deletions
+13 -11
View File
@@ -61,6 +61,7 @@ import (
"github.com/fleetdm/fleet/v4/server/service/async"
"github.com/fleetdm/fleet/v4/server/service/conditional_access_microsoft_proxy"
"github.com/fleetdm/fleet/v4/server/service/middleware/endpoint_utils"
otelmw "github.com/fleetdm/fleet/v4/server/service/middleware/otel"
"github.com/fleetdm/fleet/v4/server/service/redis_key_value"
"github.com/fleetdm/fleet/v4/server/service/redis_lock"
"github.com/fleetdm/fleet/v4/server/service/redis_policy_set"
@@ -1234,9 +1235,9 @@ the way that the Fleet server works.
launcher := launcher.New(svc, logger, grpc.NewServer(), healthCheckers)
rootMux := http.NewServeMux()
rootMux.Handle("/healthz", service.PrometheusMetricsHandler("healthz", health.Handler(httpLogger, healthCheckers)))
rootMux.Handle("/version", service.PrometheusMetricsHandler("version", version.Handler()))
rootMux.Handle("/assets/", service.PrometheusMetricsHandler("static_assets", service.ServeStaticAssets("/assets/")))
rootMux.Handle("/healthz", service.PrometheusMetricsHandler("healthz", otelmw.WrapHandler(health.Handler(httpLogger, healthCheckers), "/healthz", config)))
rootMux.Handle("/version", service.PrometheusMetricsHandler("version", otelmw.WrapHandler(version.Handler(), "/version", config)))
rootMux.Handle("/assets/", service.PrometheusMetricsHandler("static_assets", otelmw.WrapHandlerDynamic(service.ServeStaticAssets("/assets/"), config)))
if len(config.Server.PrivateKey) > 0 {
commander := apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService)
@@ -1281,6 +1282,7 @@ the way that the Fleet server works.
ddmService,
commander,
appCfg.ServerSettings.ServerURL,
config,
); err != nil {
initFatal(err, "setup mdm apple services")
}
@@ -1288,10 +1290,10 @@ the way that the Fleet server works.
if license.IsPremium() {
// SCEP proxy (for NDES, etc.)
if err = service.RegisterSCEPProxy(rootMux, ds, logger, nil); err != nil {
if err = service.RegisterSCEPProxy(rootMux, ds, logger, nil, &config); err != nil {
initFatal(err, "setup SCEP proxy")
}
if err = scim.RegisterSCIM(rootMux, ds, svc, logger); err != nil {
if err = scim.RegisterSCIM(rootMux, ds, svc, logger, &config); err != nil {
initFatal(err, "setup SCIM")
}
// Host identify SCEP feature only works if a private key has been set up
@@ -1300,7 +1302,7 @@ the way that the Fleet server works.
if err != nil {
initFatal(err, "setup host identity SCEP depot")
}
if err = hostidentity.RegisterSCEP(rootMux, hostIdentitySCEPDepot, ds, logger); err != nil {
if err = hostidentity.RegisterSCEP(rootMux, hostIdentitySCEPDepot, ds, logger, &config); err != nil {
initFatal(err, "setup host identity SCEP")
}
} else {
@@ -1312,12 +1314,12 @@ the way that the Fleet server works.
rootMux.Handle("/metrics", basicAuthHandler(
config.Prometheus.BasicAuth.Username,
config.Prometheus.BasicAuth.Password,
service.PrometheusMetricsHandler("metrics", promhttp.Handler()),
service.PrometheusMetricsHandler("metrics", otelmw.WrapHandler(promhttp.Handler(), "/metrics", config)),
))
} else {
if config.Prometheus.BasicAuth.Disable {
level.Info(logger).Log("msg", "metrics endpoint enabled with http basic auth disabled")
rootMux.Handle("/metrics", service.PrometheusMetricsHandler("metrics", promhttp.Handler()))
rootMux.Handle("/metrics", service.PrometheusMetricsHandler("metrics", otelmw.WrapHandler(promhttp.Handler(), "/metrics", config)))
} else {
level.Info(logger).Log("msg", "metrics endpoint disabled (http basic auth credentials not set)")
}
@@ -1435,13 +1437,13 @@ the way that the Fleet server works.
rootMux.Handle("/api/v1/fleet/scim/details", apiHandler)
rootMux.Handle("/api/latest/fleet/scim/details", apiHandler)
rootMux.Handle("/enroll", endUserEnrollOTAHandler)
rootMux.Handle("/", frontendHandler)
rootMux.Handle("/enroll", otelmw.WrapHandler(endUserEnrollOTAHandler, "/enroll", config))
rootMux.Handle("/", otelmw.WrapHandler(frontendHandler, "/", config))
debugHandler := &debugMux{
fleetAuthenticatedHandler: service.MakeDebugHandler(svc, config, logger, eh, ds),
}
rootMux.Handle("/debug/", debugHandler)
rootMux.Handle("/debug/", otelmw.WrapHandlerDynamic(debugHandler, config))
if debug {
// Add debug endpoints with a random