-
Notifications
You must be signed in to change notification settings - Fork 2.1k
feat: Add experimentalObservability with an OTel backend #11130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔧 Build Fix:
Two code blocks are missing required title attributes. The documentation framework requires all code blocks to have titles. The blocks at line 789 (under experimentalObservability.otel.headers) and line 812 (under experimentalObservability.otel.resource) both use the opening marker ```jsonc without a title attribute, causing the build to fail.
View Details
📝 Patch Details
diff --git a/docs/site/content/docs/reference/configuration.mdx b/docs/site/content/docs/reference/configuration.mdx
index ccce2e05e..1cb37964c 100644
--- a/docs/site/content/docs/reference/configuration.mdx
+++ b/docs/site/content/docs/reference/configuration.mdx
@@ -786,7 +786,7 @@ The OTLP collector endpoint URL. For example:
Optional HTTP headers to include with export requests. Useful for authentication (e.g., API keys) or custom metadata.
-```jsonc
+```jsonc title="./turbo.json"
{
"experimentalObservability": {
"otel": {
@@ -809,7 +809,7 @@ Timeout in milliseconds for export requests to the collector.
Optional resource attributes to attach to all exported metrics. These help identify the source of metrics in your observability platform.
-```jsonc
+```jsonc title="./turbo.json"
{
"experimentalObservability": {
"otel": {
Analysis
Missing code block titles in documentation
What fails: Next.js build fails during static page generation for the /docs/reference/configuration page. The MDX renderer requires all code blocks to have title attributes.
How to reproduce:
cd docs/site
pnpm run buildResult before fix:
Error occurred prerendering page "/docs/reference/configuration"
Error: Code blocks must have titles. If you are creating a terminal, use "Terminal" for the title. Else, add a file path name.
Result after fix:
✓ Compiled successfully in 32.7s
[Build completes successfully with all 236 pages generated]
Root cause: Two code blocks in docs/site/content/docs/reference/configuration.mdx were missing the required title attribute:
- Line 789: Code block under
experimentalObservability.otel.headers - Line 812: Code block under
experimentalObservability.otel.resource
Both blocks were changed from ```jsonc to ```jsonc title="./turbo.json" to match the pattern used throughout the documentation.
…the way it first appeared
Summary
This PR adds an experimental observability pipeline to Turborepo that can export run and task metrics via OpenTelemetry (OTLP). The feature is opt‑in: file‑based configuration (
experimentalObservabilityinturbo.json) is gated behind a future flag, while environment variables and CLI flags can enable OTEL without modifying config files. The configuration model is designed so that additional observability backends can be added later without changing the public configuration shape.Motivation
Turborepo already computes rich run summaries and per‑task metadata (durations, cache status, SCM info, etc.), but these insights were only available locally (e.g. via
--dry=json/--summarize). This change lets users send those metrics to any OTLP‑compatible collector for long‑term analysis, alerting, and correlation with other telemetry, while keeping the core CLI behavior unchanged.High‑level design
New observability abstraction
Introduces an
observabilitymodule with:RunObservertrait: “record metrics for a completed run” andshutdown.observability::Handle: an opaque, cloneable handle used by the rest ofturborepo-lib.Currently only an OTEL implementation exists, but the abstraction allows plugging in other backends later.
New
turborepo-otelcrateWraps
opentelemetry,opentelemetry-otlp, and related crates.Provides:
Config(endpoint, protocol, headers, timeout, resource attributes, metric toggles).RunMetricsPayloadandTaskMetricsPayloadstructs that encode a completed run and its tasks.Handle::try_new(config)which builds an OTLP metrics exporter (gRPC or HTTP/protobuf) and exposes:record_run(&RunMetricsPayload)shutdown()Observability configuration model
ConfigurationOptionsnow includes:experimental_observability: Option<ExperimentalObservabilityOptions>ExperimentalObservabilityOptionsis a wrapper with:otel: Option<ExperimentalOtelOptions>This mirrors the
turbo.jsonshape (experimentalObservability.otel) and leaves room for future backends to be added next tootelwithout reworking the config surface.File‑based sources (
turbo.jsonand.turbo/config.json) only populateexperimental_observabilitywhen the rootturbo.jsonhasfutureFlags.experimentalObservability: true. Env vars and CLI flags always participate in layering and are not gated by the future flag, so they can be used to experiment without changing config files.Configuration surfaces
turbo.jsonObservability is guarded by a future flag:
{ "futureFlags": { "experimentalObservability": true }, "experimentalObservability": { "otel": { "enabled": true, "protocol": "grpc", // or "http/protobuf" "endpoint": "https://collector.example.com", "headers": { "X-API-Key": "your-api-key" }, "timeoutMs": 10000, "resource": { "service.name": "turborepo" }, "metrics": { "runSummary": true, "taskDetails": false } } } }Rules:
The
experimentalObservabilityblock is only read whenfutureFlags.experimentalObservabilityistruein the rootturbo.json.For file‑based config,
experimentalObservability.otel.endpointis required; otherwise the OTEL exporter is treated as disabled.Package‑level
turbo.jsonfiles cannot defineexperimentalObservabilityorfutureFlags.Environment variables
Env vars map directly into
ExperimentalOtelOptionsand then into theexperimental_observability.otelwrapper (even if the future flag is disabled or absent):TURBO_EXPERIMENTAL_OTEL_ENABLED–1,0,true, orfalseTURBO_EXPERIMENTAL_OTEL_PROTOCOL– protocol string:grpchttp/protobuf,http, orhttp_protobufmap to the HTTP/protobuf variantTURBO_EXPERIMENTAL_OTEL_ENDPOINT– collector URLTURBO_EXPERIMENTAL_OTEL_TIMEOUT_MS– timeout in millisecondsTURBO_EXPERIMENTAL_OTEL_HEADERS– comma‑separatedkey=valuepairsTURBO_EXPERIMENTAL_OTEL_RESOURCE– comma‑separatedkey=valuepairsTURBO_EXPERIMENTAL_OTEL_METRICS_RUN_SUMMARY–1,0,true, orfalseTURBO_EXPERIMENTAL_OTEL_METRICS_TASK_DETAILS–1,0,true, orfalseParsing behavior:
Boolean env flags accept
1/0andtrue/false(other values produce a targeted configuration error that names the offending env var).TURBO_EXPERIMENTAL_OTEL_PROTOCOLrejects unsupported values with a clear configuration error.Header/resource strings must be
key=valueentries, separated by commas; malformed entries are rejected with a clear error instead of being ignored.CLI flags
New global flags provide a CLI override layer:
--experimental-otel-enabled[=true|false]--experimental-otel-protocol <grpc|http-protobuf>--experimental-otel-endpoint <URL>--experimental-otel-timeout-ms <MILLISECONDS>--experimental-otel-header KEY=VALUE(repeatable)--experimental-otel-resource KEY=VALUE(repeatable)--experimental-otel-metrics-run-summary[=true|false]--experimental-otel-metrics-task-details[=true|false]These flags are converted to
ExperimentalOtelOptionsand wrapped intoExperimentalObservabilityOptionsby the layered config builder, overriding env vars andturbo.jsonwhere provided. Like env vars, they do not depend onfutureFlags.experimentalObservabilityand can enable or tweak OTEL even when file‑based observability config is gated off.Metrics exported
Run‑level metrics (enabled by
metrics.runSummary, defaulttrue):Run duration (ms).
Number of tasks attempted, failed, and cached.
Run exit code.
SCM branch and revision (when available).
Attributes include:
turbo.run.idturbo.run.exit_codeturbo.versionturbo.scm.branchturbo.scm.revisionTask‑level metrics (enabled by
metrics.taskDetails, defaultfalse):Per‑task execution duration (ms).
Cache hit/miss events and optional cache source.
Cache time saved (ms) on hits.
Task exit code.
Identifiers for correlation:
turbo.task.idturbo.task.nameturbo.task.packageturbo.task.hashturbo.task.external_inputs_hashturbo.task.commandOTEL resource attributes:
service.namedefaults to"turborepo"but can be overridden via theresourcemap.Additional resource attributes from config are attached to all metrics.
Integration into the run lifecycle
ConfigurationOptionsnow aggregates observability configuration from:turbo.json(root only, guarded byfutureFlags.experimentalObservability)global/local config
environment variables
CLI flags
Optsexposesexperimental_observability: Option<ExperimentalObservabilityOptions>.RunBuilder:Reads
opts.experimental_observabilityand, if present, callsobservability::Handle::try_init.Stores the resulting handle on the
Runstruct.At the end of a real run, the
RunSummaryuses this handle to:Record metrics derived from the same data that powers the run summary output.
Call
shutdown()on the OTEL SDK to flush any buffered data before process exit.Dry runs (
--dry/--dry=json) do not emit OTEL metrics:Failure modes and compatibility
The feature is strictly opt‑in:
If
enabledis explicitlyfalseor no valid endpoint is configured, no exporter is created.If configuration parsing fails (bad protocol, malformed headers, invalid env flags), errors are reported as configuration errors rather than failing silently.
Exporter initialization and shutdown are non‑fatal:
If the OTLP exporter cannot be built (e.g. invalid headers, SDK errors), Turborepo logs a warning and runs without observability.
Errors during shutdown are logged but do not affect the run’s exit code.
Compile‑time feature gating:
otelCargo feature onturborepo-lib/turbo; if the binary is built without this feature, no exporter is initialized (observability config is effectively a no‑op, aside from normal config parsing/validation).Existing behavior is unchanged when observability is not configured:
No new network calls are made.
No extra metrics are emitted.
CLI and config semantics remain the same for users who don’t opt into this feature.
How to use
Deploy or point to an OTLP‑compatible collector.
In the root
turbo.json, enablefutureFlags.experimentalObservabilityand define anexperimentalObservability.otelblock with at least anendpoint(and optionalprotocol,headers, etc.), or configure via environment variables / CLI flags (which can be used even without the future flag).Start with
metrics.runSummary: trueandmetrics.taskDetails: falseto verify the setup and then opt intotaskDetailswhen more granular task metrics are useful.This PR lays the foundation for observability in Turborepo with a concrete OTEL implementation, a configuration model that supports layered overrides (file, env, CLI), and room to grow to additional backends over time.