diff --git a/docs/guides/distributed-tracing.md b/docs/guides/distributed-tracing.md index 158973a3ea..30874bc1f3 100644 --- a/docs/guides/distributed-tracing.md +++ b/docs/guides/distributed-tracing.md @@ -4,6 +4,10 @@ Platformatic supports Open Telemetry integration. This allows you to send telemetry data to one of the OTLP compatible servers ([see here](https://opentelemetry.io/ecosystem/vendors/)) or to a Zipkin server. Let's show this with [Jaeger](https://www.jaegertracing.io/). +:::tip Advanced Setup +For manual OpenTelemetry SDK setup with custom instrumentations or exporters, see the [Advanced OpenTelemetry Setup](./opentelemetry-sdk-setup.md) guide. +::: + ## Jaeger setup The quickest way is to use docker: diff --git a/docs/guides/opentelemetry-sdk-setup.md b/docs/guides/opentelemetry-sdk-setup.md new file mode 100644 index 0000000000..3b78658082 --- /dev/null +++ b/docs/guides/opentelemetry-sdk-setup.md @@ -0,0 +1,249 @@ +# Advanced OpenTelemetry Setup with Watt + +import Issues from '../getting-started/issues.md'; + +## Introduction + +Watt includes [built-in telemetry support](./distributed-tracing.md) that can be configured declaratively in your `watt.json` or `platformatic.json` files. This works well for most use cases with OTLP and Zipkin exporters. + +However, you may need manual OpenTelemetry SDK setup when you: + +- Need custom instrumentations beyond what the built-in telemetry provides +- Want to configure custom span processors or exporters +- Need fine-grained control over OpenTelemetry SDK initialization + +This guide covers how to set up the OpenTelemetry Node.js SDK manually in Watt. + +## Understanding Multi-Worker Architecture + +Watt runs each application in isolated [Node.js Worker Threads](../reference/runtime/multithread-architecture.md). This has important implications for OpenTelemetry setup: + +- **Each worker is isolated**: Every worker thread runs its own OpenTelemetry SDK instance +- **Initialization must happen early**: OpenTelemetry must load before any instrumented modules +- **Context propagation is automatic**: Watt handles trace context propagation between workers via HTTP headers + +The `execArgv` configuration with `--import` ensures your initialization script runs in each worker thread before application code loads. + +## Configuration Options + +Watt provides the `execArgv` configuration on each application to pass Node.js flags to worker threads. This is required for OpenTelemetry because the instrumentation hooks must be registered via `--import` before any application code loads. + +### Application-Level Configuration + +Use the `execArgv` option on each application to configure OpenTelemetry: + +```json +{ + "$schema": "https://schemas.platformatic.dev/wattpm/3.0.0.json", + "applications": [ + { + "id": "api", + "path": "./services/api", + "execArgv": [ + "--import", "@opentelemetry/instrumentation/hook.mjs", + "--import", "./telemetry-init.mjs" + ] + } + ], + "server": { + "port": 3000 + } +} +``` + +### Multiple Applications + +When you have multiple applications, each needs its own `execArgv` configuration: + +```json +{ + "$schema": "https://schemas.platformatic.dev/wattpm/3.0.0.json", + "applications": [ + { + "id": "api", + "path": "./services/api", + "execArgv": [ + "--import", "@opentelemetry/instrumentation/hook.mjs", + "--import", "./telemetry-init.mjs" + ] + }, + { + "id": "worker", + "path": "./services/worker", + "execArgv": [ + "--import", "@opentelemetry/instrumentation/hook.mjs", + "--import", "./telemetry-init.mjs" + ] + } + ] +} +``` + +## Initialization Script + +The initialization script configures the OpenTelemetry SDK and must be loaded before any application code. Here's a complete example: + +```javascript +// telemetry-init.mjs +import { workerData } from 'node:worker_threads' +import { NodeSDK } from '@opentelemetry/sdk-node' +import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node' +import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' +import { Resource } from '@opentelemetry/resources' +import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions' + +// Get service name from workerData (set by Platformatic) +const serviceName = workerData?.applicationConfig?.id || 'unknown-service' + +const sdk = new NodeSDK({ + resource: new Resource({ + [ATTR_SERVICE_NAME]: serviceName, + [ATTR_SERVICE_VERSION]: process.env.OTEL_SERVICE_VERSION || '1.0.0' + }), + traceExporter: new OTLPTraceExporter({ + url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces', + headers: process.env.OTEL_EXPORTER_OTLP_HEADERS + ? JSON.parse(process.env.OTEL_EXPORTER_OTLP_HEADERS) + : {} + }), + instrumentations: [ + getNodeAutoInstrumentations({ + // Disable specific instrumentations if needed + '@opentelemetry/instrumentation-fs': { enabled: false } + }) + ] +}) + +sdk.start() + +// Graceful shutdown to flush pending spans +process.on('SIGTERM', () => { + sdk.shutdown() + .then(() => console.log('Telemetry terminated')) + .catch((error) => console.log('Error terminating telemetry', error)) + .finally(() => process.exit(0)) +}) +``` + +The `workerData` object is automatically set by Watt for each worker thread and contains the application configuration. The `applicationConfig.id` property holds the service identifier as defined in your `watt.json`. + +### Why the Hook is Required + +The module loading order is critical: + +1. Node.js processes `--import` flags in order before the application starts +2. The OpenTelemetry hook registers loader hooks to intercept module imports +3. Your initialization script configures and starts the SDK +4. Application code loads (instrumentation is applied via the hook) + +Without the hook, OpenTelemetry cannot intercept imports and instrumentation will not work. + +### Disabling Built-in Telemetry + +When using manual SDK setup, you should disable Watt's built-in telemetry to avoid conflicts (duplicate spans, multiple exporters, etc.): + +```json +{ + "applications": [ + { + "id": "api", + "path": "./services/api", + "execArgv": [ + "--import", "@opentelemetry/instrumentation/hook.mjs", + "--import", "./telemetry-init.mjs" + ], + "telemetry": { + "enabled": false + } + } + ] +} +``` + +## Troubleshooting + +### Telemetry Not Appearing + +1. **Check module loading order**: Ensure OpenTelemetry loads before application code +2. **Verify exporter URL**: Confirm the collector endpoint is accessible +3. **Check for errors**: Look for initialization errors in logs +4. **Validate configuration**: Ensure environment variables are set correctly + +### Module Loading Errors + +Common issues: + +- **"Cannot use import statement outside a module"**: Ensure your initialization file has `.mjs` extension +- **Module not found**: Check the import path is correct and the package is installed + +### OpenTelemetry SDK Not Initializing + +1. Verify all required environment variables are set +2. Ensure the module path in `execArgv` is correct and the module exists +3. Check for initialization errors in the console output +4. Verify the OTLP endpoint is accessible from the application + +## Complete Example with Jaeger + +**watt.json:** +```json +{ + "$schema": "https://schemas.platformatic.dev/wattpm/3.0.0.json", + "entrypoint": "api", + "applications": [ + { + "id": "api", + "path": "./services/api", + "execArgv": [ + "--import", "@opentelemetry/instrumentation/hook.mjs", + "--import", "./telemetry.mjs" + ] + } + ], + "env": { + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318/v1/traces" + }, + "server": { + "port": 3000 + } +} +``` + +**telemetry.mjs:** +```javascript +import { workerData } from 'node:worker_threads' +import { NodeSDK } from '@opentelemetry/sdk-node' +import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node' +import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' +import { Resource } from '@opentelemetry/resources' +import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions' + +// Get service name from workerData (set by Platformatic) +const serviceName = workerData?.applicationConfig?.id || 'unknown-service' + +const sdk = new NodeSDK({ + resource: new Resource({ + [ATTR_SERVICE_NAME]: serviceName + }), + traceExporter: new OTLPTraceExporter({ + url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + }), + instrumentations: [getNodeAutoInstrumentations()] +}) + +sdk.start() + +process.on('SIGTERM', () => sdk.shutdown()) +``` + +**Start Jaeger:** +```bash +docker run -d --name jaeger \ + -e COLLECTOR_OTLP_ENABLED=true \ + -p 16686:16686 \ + -p 4317:4317 \ + -p 4318:4318 \ + jaegertracing/all-in-one:latest +``` + + diff --git a/package-lock.json b/package-lock.json index 30818fad54..7876d90571 100644 --- a/package-lock.json +++ b/package-lock.json @@ -252,6 +252,7 @@ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.39.0.tgz", "integrity": "sha512-/IYpF10BpthGZEJQZMhMqV4AqWr5avcWfZm/SIKK1RvUDmzGqLoW/+xeJVX9C8ZnNkIC8hivbIQFaNaRw0BFZQ==", "license": "MIT", + "peer": true, "dependencies": { "@algolia/client-common": "5.39.0", "@algolia/requester-browser-xhr": "5.39.0", @@ -431,6 +432,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2220,6 +2222,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -2242,6 +2245,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -2351,6 +2355,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -2772,6 +2777,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -3815,6 +3821,7 @@ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.1.tgz", "integrity": "sha512-DyLk9BIA6I9gPIuia8XIL+XIEbNnExam6AHzRsfrEq4zJr7k/DsWW7oi4aJMepDnL7jMRhpVcdsCxdjb0/A9xg==", "license": "MIT", + "peer": true, "dependencies": { "@docusaurus/core": "3.9.1", "@docusaurus/logger": "3.9.1", @@ -5423,6 +5430,7 @@ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "license": "MIT", + "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -5522,6 +5530,7 @@ "resolved": "https://registry.npmjs.org/@orama/orama/-/orama-3.1.14.tgz", "integrity": "sha512-Iq4RxYC7y0pA/hLgcUGpYYs5Vze4qNmJk0Qi1uIrg2bHGpm6A06nbjWcH9h4HQsddkDFFlanLj/zYBH3Sxdb4w==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">= 20.0.0" } @@ -5585,6 +5594,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -6345,6 +6355,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -6363,6 +6374,7 @@ "resolved": "https://registry.npmjs.org/@oramacloud/client/-/client-2.1.4.tgz", "integrity": "sha512-uNPFs4wq/iOPbggCwTkVNbIr64Vfd7ZS/h+cricXVnzXWocjDTfJ3wLL4lr0qiSu41g8z+eCAGBqJ30RO2O4AA==", "license": "ISC", + "peer": true, "dependencies": { "@orama/cuid2": "^2.2.3", "@orama/orama": "^3.0.0", @@ -6969,6 +6981,7 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -7365,6 +7378,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.0.tgz", "integrity": "sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -7700,6 +7714,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7794,6 +7809,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -7839,6 +7855,7 @@ "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.39.0.tgz", "integrity": "sha512-DzTfhUxzg9QBNGzU/0kZkxEV72TeA4MmPJ7RVfLnQwHNhhliPo7ynglEWJS791rNlLFoTyrKvkapwr/P3EXV9A==", "license": "MIT", + "peer": true, "dependencies": { "@algolia/abtesting": "1.5.0", "@algolia/client-abtesting": "5.39.0", @@ -8818,6 +8835,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -10676,6 +10694,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -12010,6 +12029,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -12217,6 +12237,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -12308,6 +12329,7 @@ "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", @@ -12358,6 +12380,7 @@ "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -12374,6 +12397,7 @@ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -13320,6 +13344,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17310,6 +17335,7 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-16.3.0.tgz", "integrity": "sha512-K3UxuKu6l6bmA5FUwYho8CfJBlsUWAooKtdGgMcERSpF7gcBUrCGsLH7wDaaNOzwq18JzSUDyoEb/YsrqMac3w==", "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -22466,6 +22492,7 @@ "version": "4.0.2", "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -22739,6 +22766,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -23772,6 +23800,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -24784,6 +24813,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -25725,6 +25755,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -25737,6 +25768,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -25793,6 +25825,7 @@ "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/react": "*" }, @@ -25827,6 +25860,7 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -32293,7 +32327,8 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/type-check": { "version": "0.4.0", @@ -32973,6 +33008,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -33305,6 +33341,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.0.tgz", "integrity": "sha512-hUtqAR3ZLVEYDEABdBioQCIqSoguHbFn1K7WlPPWSuXmx0031BD73PSE35jKyftdSh4YLDoQNgK4pqBt5Q82MA==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -34199,6 +34236,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.11.tgz", "integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/sidebars.json b/sidebars.json index fd955ee62e..9230ea8190 100644 --- a/sidebars.json +++ b/sidebars.json @@ -65,6 +65,7 @@ "items": [ "guides/metrics", "guides/distributed-tracing", + "guides/opentelemetry-sdk-setup", "guides/logging-to-elasticsearch", "guides/profiling-with-watt", "guides/debugging-with-repl"