UNPKG

@vtex/diagnostics-nodejs

Version:

Diagnostics library for Node.js applications

1,326 lines (1,133 loc) 32.6 kB
# OpenTelemetry Diagnostics Library for Node.js A comprehensive Node.js library that simplifies telemetry collection using OpenTelemetry, providing unified interfaces for metrics, logs, and traces with advanced sampling, hot-reload configuration, and easy-to-use instrumentation setups for popular frameworks. ## Features ✅ **Unified Telemetry**: Metrics, logs, and traces in one library ✅ **Auto-Instrumentation**: Express, Fastify, Koa, NestJS support ✅ **Advanced Sampling**: Rule-based, parent-based, debug override, hot-reload ✅ **Remote Configuration**: File-based, S3, with live reload and polling ✅ **Configuration Override**: Runtime config updates and hot-swapping ✅ **Resource Discovery**: Automatic cloud and Kubernetes detection ✅ **Context Propagation**: Baggage and trace context across services ✅ **Custom Processors**: VTEX-specific attribute enrichment ✅ **Distributed Resampling**: Override parent sampling decisions ✅ **gRPC Export**: High-performance OTLP export ## Installation ```bash npm install @vtex/diagnostics-nodejs ``` ## Quick Start ```javascript import { NewTelemetryClient, Instrumentation } from '@vtex/diagnostics-nodejs'; async function main() { // 1. Define your instrumentations const instrumentations = Instrumentation.CommonInstrumentations.express(); // 2. Initialize telemetry client BEFORE importing frameworks const telemetryClient = await NewTelemetryClient( 'my-app-id', // Application ID 'my-client-instance', // Client instance name 'my-service-name' // Service name ); // 3. Create telemetry clients const tracesClient = await telemetryClient.newTracesClient({ setGlobalProvider: true, }); const metricsClient = await telemetryClient.newMetricsClient(); const logsClient = await telemetryClient.newLogsClient(); // 4. Register the instrumentations. This activates them. telemetryClient.registerInstrumentations(instrumentations); // 5. NOW import your frameworks const express = require('express'); const app = express(); // Your app is automatically instrumented! app.get('/api/users', (req, res) => { logsClient.info('Users endpoint called', { userId: req.query.id }); res.json({ users: [] }); }); app.listen(3000); } main().catch(console.error); ``` ## Remote Configuration Management ### File-Based Configuration with Hot Reload ```javascript const telemetryClient = await NewTelemetryClient( 'my-app-id', 'my-client', 'my-service', { config: { configPath: './config/telemetry.json', enableHotReload: true, // Enable live reload pollIntervalMs: 15000 // Check for changes every 15s } } ); // Config changes are automatically applied without restart! // Watch logs for: "🔄 Hot reloading sampling configuration..." ``` ### S3-Based Remote Configuration ```javascript const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { config: { s3Config: { bucket: 'my-telemetry-configs', key: 'environments/prod/my-service.json', region: 'us-east-1' }, pollIntervalMs: 30000, // Poll S3 every 30s enableHotReload: true } } ); // Centralized config management: // 1. Update config in S3 // 2. All instances pick up changes automatically // 3. No service restarts required ``` ### Configuration Override at Runtime ```javascript // The ConfigManager is an internal component and not exposed via a public `getConfigManager()` method. // Configuration updates are handled automatically via file/S3 polling when `enableHotReload` is true. // The `onConfigChange` functionality would require implementing a custom configuration provider. console.log('Configuration from file/S3 will be hot-reloaded automatically if enabled.'); ``` ### Environment-Specific Configuration ```javascript // Base configuration const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { config: { configPath: `./config/${process.env.NODE_ENV || 'development'}.json`, enableHotReload: process.env.NODE_ENV !== 'production' }, // Override config based on environment environment: process.env.DEPLOYMENT_ENV, region: process.env.AWS_REGION, // Additional runtime attributes additionalAttrs: { 'deployment.version': process.env.GIT_SHA, 'deployment.timestamp': new Date().toISOString() } } ); ``` ### Using Configuration Files ```javascript const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { config: { configPath: './config/telemetry.json', enableHotReload: true, pollIntervalMs: 15000 } } ); ``` ### Configuration Override Examples ```json // Development: High sampling for debugging // config/development.json { "traces": { "sampling": { "defaultRate": 1.0, "rules": [ { "name": "debug_everything", "sampleRate": 1.0, "conditions": [] } ] } } } ```json // Production: Selective sampling // config/production.json { "traces": { "sampling": { "defaultRate": 0.01, "rules": [ { "name": "critical_endpoints", "sampleRate": 1.0, "conditions": [ { "attribute": "http.target", "operator": "Regex", "value": "^/api/(checkout|payment|auth)" } ] }, { "name": "error_traces", "sampleRate": 1.0, "conditions": [ { "attribute": "http.status_code", "operator": "GreaterThanEqual", "value": "400" } ] } ] } } } ``` ### Live Configuration Updates ```javascript // Monitor configuration changes in real-time const telemetryClient = await NewTelemetryClient('app', 'client', 'service', { config: { enableHotReload: true } }); // Define instrumentations const instrumentations = Instrumentation.CommonInstrumentations.autoDetect(); // Initialize clients const tracesClient = await telemetryClient.newTracesClient(); // Register instrumentations telemetryClient.registerInstrumentations(instrumentations); // Example: Change sampling rules via file edit // 1. Edit config/telemetry.json // 2. Change defaultRate from 0.1 to 0.5 // 3. Save file // 4. Library automatically detects change // 5. New sampling rules applied within seconds // 6. See logs: "🔄 Hot reloading sampling configuration..." console.log('Config will auto-reload from file changes...'); ``` ### Conditional Configuration Loading ```javascript async function createTelemetryClient() { const isProd = process.env.NODE_ENV === 'production'; const isK8s = !!process.env.KUBERNETES_SERVICE_HOST; const config = { config: { // Production: Use S3 remote config ...(isProd && { s3Config: { bucket: 'prod-telemetry-configs', key: `services/${process.env.SERVICE_NAME}/config.json`, region: process.env.AWS_REGION } }), // Development: Use local file ...(!isProd && { configPath: './config/dev.json' }), enableHotReload: true, pollIntervalMs: isProd ? 60000 : 15000 // Slower polling in prod }, // Kubernetes-specific attributes ...(isK8s && { additionalAttrs: { 'k8s.namespace': process.env.KUBERNETES_NAMESPACE, 'k8s.pod': process.env.HOSTNAME, 'k8s.node': process.env.NODE_NAME } }), disableCloudDetect: !isProd, debug: !isProd }; return await NewTelemetryClient('app', 'client', 'service', config); } ``` ### Global vs Service-Specific Configuration ```json // Hierarchical configuration override const baseConfig = { "globalResourceAttributes": { "service.namespace": "ecommerce", "deployment.environment": "production" }, "traces": { "exporters": { "mode": "otlp", "otlp": { "endpoint": "otel-collector:4317" } }, "sampling": { "parentBased": true, "defaultRate": 0.05 } } }; ```json // Service-specific overrides const serviceOverrides = { "user-service": { "traces": { "sampling": { "defaultRate": 0.1, "rules": [ { "name": "auth_endpoints", "sampleRate": 1.0, "conditions": [ { "attribute": "http.target", "operator": "StartsWith", "value": "/auth" } ] } ] } } }, "payment-service": { "traces": { "sampling": { "defaultRate": 1.0, "parentBased": false } } }, "inventory-service": { "traces": { "sampling": { "parentBased": false, "defaultRate": 0.01, "rules": [ { "name": "resample_checkout_flow", "sampleRate": 1.0, "conditions": [ { "attribute": "http.target", "operator": "Contains", "value": "checkout" } ] } ] } } } }; ```json { "environment": "production", "globalResourceAttributes": { "service.namespace": "ecommerce", "deployment.environment": "prod" }, "traces": { "exporters": { "mode": "otlp", "otlp": { "endpoint": "otel-collector:4317" } }, "sampling": { "parentBased": true, "defaultRate": 0.1, "rules": [ { "name": "sample_critical_endpoints", "sampleRate": 1.0, "conditions": [ { "attribute": "http.target", "operator": "StartsWith", "value": "/api/checkout" } ] }, { "name": "debug_override", "sampleRate": 1.0, "conditions": [ { "attribute": "debug", "operator": "Equals", "value": "true" } ] } ] } } } ``` ## Advanced Sampling ### Rule-Based Sampling Control sampling with flexible rules that support hot-reload: ```json // Configuration supports multiple operators and conditions { "sampling": { "parentBased": true, "defaultRate": 0.05, "rules": [ { "name": "high_priority_routes", "sampleRate": 1.0, "conditions": [ { "attribute": "http.method", "operator": "Equals", "value": "POST" }, { "attribute": "http.target", "operator": "Regex", "value": "^/api/(orders|payments)" } ] } ] } } ``` ### Resampling in Distributed Traces Override parent sampling decisions in specific services: ```json // Service A: parentBased: true (follows upstream decisions) // Service B: parentBased: false (makes independent decisions) { "sampling": { "parentBased": false, "rules": [ { "name": "force_sample_inventory_operations", "sampleRate": 1.0, "conditions": [...] } ] } } ``` ### Debug Sampling Force sampling with debug flags: ```bash # Always samples when debug is present curl "http://api/users?debug=true" curl -H "debug: true" http://api/users ``` ### Supported Sampling Operators - `Equals`, `NotEquals` - `Contains`, `StartsWith`, `EndsWith` - `In`, `NotIn` (arrays) - `Regex` - `GreaterThan`, `LessThan`, `GreaterThanEqual`, `LessThanEqual` ## Instrumentation ### Framework Support ```javascript // Choose your framework bundle const instrumentations = { express: Instrumentation.CommonInstrumentations.express(), fastify: Instrumentation.CommonInstrumentations.fastify(), koa: Instrumentation.CommonInstrumentations.koa(), nestjs: Instrumentation.CommonInstrumentations.nestjs(), minimal: Instrumentation.CommonInstrumentations.minimal(), // HTTP only autoDetect: Instrumentation.CommonInstrumentations.autoDetect() }; ``` ### Adding Database & External Service Tracing ```javascript import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'; import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis'; import { NewTelemetryClient, Instrumentation } from '@vtex/diagnostics-nodejs'; async function setup() { // 1. Create a list of all desired instrumentations const myInstrumentations = [ ...Instrumentation.CommonInstrumentations.express(), new MongoDBInstrumentation(), new RedisInstrumentation(), // Add any other OpenTelemetry community instrumentation ]; // 2. Initialize the client const telemetryClient = await NewTelemetryClient('app-id', 'client-name', 'service-name'); await telemetryClient.newTracesClient(); // and other clients // 3. Register all instrumentations telemetryClient.registerInstrumentations(myInstrumentations); } ``` ## Context Propagation & Baggage ### Adding Baggage ```javascript import { Traces } from '@vtex/diagnostics-nodejs'; app.get('/api/users', (req, res) => { // Add baggage items that propagate to downstream services Traces.addBaggage({ 'user.id': req.user.id, 'request.priority': 'high', 'trace.source': 'web-app' }); // Single baggage item Traces.setBaggage('operation.type', 'user-lookup'); // Retrieve baggage const baggage = Traces.getActiveBaggage(); console.log('Current baggage:', baggage); }); ``` ### Middleware for Context Propagation ```javascript import { Instrumentation } from '@vtex/diagnostics-nodejs'; // Express app.use(Instrumentation.Middlewares.ContextMiddlewares.Express.ContextPropagationMiddleware()); // Fastify fastify.register(Instrumentation.Middlewares.ContextMiddlewares.Fastify.createContextPlugin()); // Koa app.use(Instrumentation.Middlewares.ContextMiddlewares.Koa.ContextPropagationMiddleware()); ``` ## Manual Tracing ### Creating Custom Spans ```javascript const span = tracesClient.startSpan('database-migration', { attributes: { 'migration.version': '1.2.0' }, kind: SpanKind.INTERNAL }); try { span.setAttributes({ 'migration.tables': ['users', 'orders'], 'migration.duration_estimate': '5min' }); span.addEvent('migration-started', { timestamp: Date.now() }); // Your operation await runMigration(); span.addEvent('migration-completed'); } catch (error) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); throw error; } finally { span.end(); } ``` ### Trace Context Injection/Extraction ```javascript // Inject trace context into HTTP headers const headers = {}; tracesClient.inject(headers); console.log(headers); // { traceparent: "00-...", tracestate: "..." } // Extract trace context from incoming headers const context = tracesClient.extract(req.headers); context.execute(() => { // Code executed within the extracted trace context logsClient.info('Processing with extracted context'); }); ``` ## Metrics ### Counter Metrics ```javascript import { Metrics } from '@vtex/diagnostics-nodejs'; const httpRequestsCounter = metricsClient.createCounter( 'http_requests_total', { description: 'Total HTTP requests processed', unit: '1' } ); // Increment counter httpRequestsCounter.increment({ method: 'GET', status: '200' }); httpRequestsCounter.add(5, { method: 'POST', status: '201' }); ``` ### Histogram Metrics ```javascript const responseTimeHistogram = metricsClient.createHistogram( 'http_response_time_seconds', { description: 'HTTP response time distribution', unit: 's', boundaries: [0.01, 0.05, 0.1, 0.5, 1, 5, 10] } ); responseTimeHistogram.record(0.145, { route: '/api/users', method: 'GET' }); ``` ### Gauge Metrics ```javascript const activeConnectionsGauge = metricsClient.createGauge( 'active_connections', { description: 'Current active database connections' } ); activeConnectionsGauge.set(42); activeConnectionsGauge.add(5); // Increment by 5 activeConnectionsGauge.subtract(2); // Decrement by 2 ``` ## Structured Logging ### Log Levels & Attributes ```javascript // Structured logging with attributes logsClient.info('User login successful', { 'user.id': '12345', 'login.method': 'oauth', 'client.ip': req.ip, 'vtex.search_index': 'user_events' // Custom attributes }); logsClient.warn('Rate limit approaching', { 'rate_limit.current': 95, 'rate_limit.max': 100, 'time_window': '1min' }); logsClient.error('Database query failed', { 'query.table': 'users', 'query.duration_ms': 5000, 'error.type': 'timeout' }); ``` ### Log Correlation with Traces Logs automatically include trace context when created within an active span: ```javascript const span = tracesClient.startSpan('process-order'); // Logs will automatically include trace and span IDs logsClient.info('Processing order', { orderId: '12345' }); span.end(); ``` ## Resource Discovery ### Automatic Attribute Detection ```javascript const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { // Environment variable mappings envMappings: [ { envVar: 'REGION', attributeName: 'cloud.region' }, { envVar: 'VERSION', attributeName: 'service.version' } ], // Additional static attributes additionalAttrs: { 'service.team': 'platform', 'service.tier': 'critical' }, // Cloud detection disableCloudDetect: false, // Auto-detect AWS/GCP/Azure disableK8sDetect: false, // Auto-detect Kubernetes // Environment and region environment: 'production', region: 'us-east-1' } ); ``` ### Custom Attributes from Files ```json // Read attributes from JSON file { "customAttributesFile": "./custom-attributes.json" } ```json // custom-attributes.json { "environmentVariables": { "POD_NAME": "k8s.pod.name", "NODE_NAME": "k8s.node.name" }, "attributes": { "service.owner": "platform-team", "cost.center": "engineering" } } ``` ## Export Configuration ### OTLP gRPC Export ```javascript // Local development (insecure) const tracesClient = await telemetryClient.newTracesClient({ exporter: CreateExporter( CreateTracesExporterConfig({ endpoint: 'localhost:4317', compression: 'gzip', timeoutSeconds: 30 }), 'otlp' ) }); ```javascript // Production (secure) const tracesClient = await telemetryClient.newTracesClient({ exporter: CreateExporter( CreateTracesExporterConfig({ endpoint: 'otel-collector.company.com:443', compression: 'gzip', insecure: false }), 'otlp' ) }); ``` ### Console Export (Development) ```javascript const tracesClient = await telemetryClient.newTracesClient({ exporter: CreateExporter( CreateTracesExporterConfig({ endpoint: 'stdout' }), 'stdout' ) }); ``` ## Advanced Configuration ### Configuration Providers ```javascript // File Provider (local development) import { ConfigManager, FileConfigProvider } from '@vtex/diagnostics-nodejs'; const configManager = new ConfigManager('my-app', 'my-service', { configPath: './config/telemetry.json', enableHotReload: true }); ```javascript // S3 Provider (production) import { S3ConfigProvider } from '@vtex/diagnostics-nodejs'; const s3Provider = new S3ConfigProvider( 'telemetry-configs-bucket', 'services/my-service/config.json', 'us-east-1', 30000 // Poll interval ); ```javascript // Custom provider implementation class CustomConfigProvider { async load() { // Fetch from your custom source (API, database, etc.) return { traces: { sampling: { defaultRate: await this.getSamplingRateFromAPI() } } }; } onChange(callback) { // Subscribe to config changes this.webhookSubscriber.on('config-changed', callback); } } ``` ### Environment Variable Mappings ```javascript const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { // Map environment variables to resource attributes envMappings: [ { envVar: 'REGION', attributeName: 'cloud.region' }, { envVar: 'VERSION', attributeName: 'service.version' }, { envVar: 'TEAM', attributeName: 'service.team' }, { envVar: 'POD_NAME', attributeName: 'k8s.pod.name' }, { envVar: 'NODE_NAME', attributeName: 'k8s.node.name' } ], // Prefix-based mapping (maps all TELEMETRY_ATTR_* vars) envPrefix: 'TELEMETRY_ATTR_', disableEnvPrefixDetection: false, // Custom attributes file customAttributesFile: './custom-attributes.json' } ); // Environment variables automatically mapped: // REGION=us-east-1 → cloud.region=us-east-1 // VERSION=1.2.3 → service.version=1.2.3 // TELEMETRY_ATTR_COST_CENTER=eng → cost.center=eng ``` ```javascript const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { config: { s3Config: { bucket: 'my-telemetry-configs', key: 'services/my-service/config.json', region: 'us-east-1' }, pollIntervalMs: 30000 } } ); ``` ## Advanced Features ### Configuration Validation & Error Handling ```javascript const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { config: { configPath: './config/telemetry.json', enableHotReload: true, // Validation options validateConfig: true, fallbackToDefaults: true, // Use defaults if config is invalid // Error handling onConfigError: (error) => { console.error('Config error:', error); // Send alert, fallback to safe defaults, etc. }, onConfigChange: (newConfig, oldConfig) => { console.log('Config changed:', { oldSamplingRate: oldConfig.traces?.sampling?.defaultRate, newSamplingRate: newConfig.traces?.sampling?.defaultRate }); } } } ); ``` ### Feature Flags Integration ```json // Dynamic feature flags with configuration { "features": { "enableAdvancedSampling": true, "enableCustomProcessors": true, "enableBaggagePropagation": true }, "traces": { "sampling": { "defaultRate": "{{features.enableAdvancedSampling ? 0.1 : 0.01}}", "rules": [ { "name": "feature_flag_sampling", "sampleRate": 1.0, "enabled": "{{features.enableAdvancedSampling}}", "conditions": [ { "attribute": "feature.flag", "operator": "Equals", "value": "new_checkout" } ] } ] } } } ``` ### Multi-Environment Configuration ```json // config/base.json (shared configuration) { "globalResourceAttributes": { "service.namespace": "ecommerce" }, "traces": { "exporters": { "mode": "otlp" } } } ```json // config/production.json (production overrides) { "extends": "./base.json", "globalResourceAttributes": { "deployment.environment": "production" }, "traces": { "exporters": { "otlp": { "endpoint": "prod-collector:4317" } }, "sampling": { "defaultRate": 0.01 } } } ```json // config/development.json (development overrides) { "extends": "./base.json", "globalResourceAttributes": { "deployment.environment": "development" }, "traces": { "exporters": { "otlp": { "endpoint": "localhost:4317" } }, "sampling": { "defaultRate": 1.0 } } } ``` ### Circuit Breaker Configuration ```json // Automatic fallback when OTLP collector is down { "traces": { "exporters": { "mode": "otlp", "otlp": { "endpoint": "otel-collector:4317", "timeoutMs": 5000, "maxRetries": 3 }, "fallback": { "mode": "console", "enabled": true } }, "circuitBreaker": { "enabled": true, "failureThreshold": 5, "recoveryTimeMs": 30000 } } } ``` ```javascript import { Processors } from '@vtex/diagnostics-nodejs'; const telemetryClient = await NewTelemetryClient(...); const tracesClient = await telemetryClient.newTracesClient({ // VTEX-specific attribute processor (enabled by default) enableVtexProcessor: true, vtexProcessorConfig: { customAttributes: { 'vtex.workspace': process.env.VTEX_WORKSPACE } }, // Baggage processor (enabled by default) enableBaggageProcessor: true }); ``` ### Performance & Resource Management ```json // Fine-tune performance settings { "traces": { "batchTimeoutMs": 5000, "maxBatchSize": 512, "maxQueueSize": 2048, "useSimpleProcessor": false }, "metrics": { "exportIntervalMs": 30000, "maxMetricsPoints": 1000, "cardinalityLimit": 1000 }, "logs": { "batchTimeoutMs": 1000, "maxBatchSize": 100, "maxQueueSize": 500 } } ``` ### Configuration Security ```json // Secure configuration with encrypted values { "traces": { "exporters": { "otlp": { "endpoint": "{{decrypt:aws-kms:endpoint}}", "headers": { "authorization": "{{env:OTEL_API_KEY}}" } } } }, "encryption": { "provider": "aws-kms", "keyId": "arn:aws:kms:us-east-1:123456789:key/12345678" } } ```javascript // Runtime decryption const telemetryClient = await NewTelemetryClient( 'my-app', 'my-client', 'my-service', { config: { configPath: './config/encrypted.json', decryptionProvider: new AWSKMSDecryption(), enableConfigValidation: true } } ); ``` ### Custom Processors ```javascript import { Processors } from '@vtex/diagnostics-nodejs'; const telemetryClient = await NewTelemetryClient(...); const tracesClient = await telemetryClient.newTracesClient({ // Built-in VTEX processor (enabled by default) enableVtexProcessor: true, vtexProcessorConfig: { customAttributes: { 'vtex.workspace': process.env.VTEX_WORKSPACE, 'vtex.account': process.env.VTEX_ACCOUNT } }, // Baggage processor (enabled by default) enableBaggageProcessor: true, // Custom span processor customProcessors: [ new MyCustomSpanProcessor({ addTimestamp: true, enrichWithBusinessContext: true }) ] }); ``` ```javascript // Before: Manual OpenTelemetry setup const tracer = trace.getTracer('my-service'); const meter = metrics.getMeter('my-service'); // After: Diagnostics library const telemetryClient = await NewTelemetryClient('app', 'client', 'service'); const instrumentations = Instrumentation.CommonInstrumentations.autoDetect(); const tracesClient = await telemetryClient.newTracesClient(); const metricsClient = await telemetryClient.newMetricsClient(); telemetryClient.registerInstrumentations(instrumentations); ``` ## Troubleshooting ### Common Issues 1. **No traces generated**: Ensure telemetry client is initialized and instrumentations are registered *before* importing frameworks. 2. **Sampling not working**: Check `http.target` attribute in rules (not `http.route`). 3. **Config not reloading**: Verify file permissions and polling interval. 4. **gRPC connection failed**: Use correct port (4317 for insecure, 443 for TLS). 5. **S3 config not loading**: Check AWS credentials and bucket permissions. 6. **High memory usage**: Reduce batch sizes and queue limits in the configuration. 7. **Missing baggage**: Ensure context propagation middleware is installed and used correctly. ### Debug & Monitoring ```javascript // Enable comprehensive debugging const telemetryClient = await NewTelemetryClient( 'app', 'client', 'service', { debug: true, // OpenTelemetry debug logs config: { enableHotReload: true, onConfigError: (error) => console.error('Config error:', error), onConfigChange: (newConfig) => console.log('Config updated:', newConfig) } } ); // The ConfigManager is internal and not exposed via a public `getConfigManager()` method. // To monitor config, use the `onConfigChange` callback in the config options. // Check sampling decisions by enabling debug logs or creating a custom span processor. ``` ### Performance Monitoring ```javascript // Monitor telemetry overhead const telemetryMetrics = metricsClient.createHistogram('telemetry_overhead_ms'); const configReloadCounter = metricsClient.createCounter('config_reloads_total'); // The onConfigChange callback can be used to increment the counter. // Example: // onConfigChange: (newConfig) => { // configReloadCounter.increment(); // } // Monitoring export success/failure would require custom exporters or processors. ``` ### Debug Logging ```javascript const telemetryClient = await NewTelemetryClient( 'app', 'client', 'service', { debug: true } // Enables OpenTelemetry debug logs ); ``` ## Examples & Use Cases ### Microservices with Remote Configuration ```bash # Centralized configuration management my-microservices/ ├── services/ │ ├── api-gateway/ # parentBased: true, high sampling │ ├── user-service/ # parentBased: true, follows gateway │ ├── inventory/ # parentBased: false, resamples │ └── payment/ # parentBased: true, 100% sampling ├── configs/ │ ├── s3-bucket: telemetry-configs │ ├── api-gateway.json │ ├── user-service.json │ ├── inventory.json │ └── payment.json └── shared/ └── base-config.json ``` ### A/B Testing with Configuration ```json // Dynamic sampling based on feature flags { "traces": { "sampling": { "rules": [ { "name": "new_checkout_flow", "sampleRate": 1.0, "conditions": [ { "attribute": "feature.checkout_v2", "operator": "Equals", "value": "true" } ] }, { "name": "legacy_checkout_flow", "sampleRate": 0.1, "conditions": [ { "attribute": "feature.checkout_v2", "operator": "Equals", "value": "false" } ] } ] } } } ```javascript // Usage in code app.post('/checkout', (req, res) => { const useNewCheckout = featureFlag.isEnabled('checkout_v2', req.user.id); Traces.addBaggage({ 'feature.checkout_v2': useNewCheckout.toString(), 'user.segment': req.user.segment }); // Automatically sampled based on feature flag }); ``` ### Disaster Recovery Configuration ```json // Multi-region failover { "traces": { "exporters": { "primary": { "mode": "otlp", "otlp": { "endpoint": "us-east-1-collector:4317" } }, "secondary": { "mode": "otlp", "otlp": { "endpoint": "us-west-2-collector:4317" } }, "fallback": { "mode": "console" } }, "failover": { "enabled": true, "healthCheckIntervalMs": 10000, "failoverTimeoutMs": 5000 } } } ``` ### Cost Optimization ```json // Smart sampling for cost control { "traces": { "sampling": { "defaultRate": 0.001, "rules": [ { "name": "errors_always", "sampleRate": 1.0, "conditions": [ { "attribute": "http.status_code", "operator": "GreaterThanEqual", "value": "400" } ] }, { "name": "slow_requests", "sampleRate": 1.0, "conditions": [ { "attribute": "http.response_time_ms", "operator": "GreaterThan", "value": "1000" } ] }, { "name": "business_critical", "sampleRate": 0.1, "conditions": [ { "attribute": "http.target", "operator": "Regex", "value": "^/api/(checkout|payment|auth)" } ] }, { "name": "high_value_users", "sampleRate": 0.5, "conditions": [ { "attribute": "user.tier", "operator": "Equals", "value": "premium" } ] } ] } } } ``` ## Migration from Basic OpenTelemetry - [Express with Auto-Instrumentation](../../../examples/javascript/nodejs/nodejs-server/) - [Microservices with Distributed Tracing](../../../examples/javascript/nodejs/nodejs-server/) - [Custom Sampling Rules](../../../examples/javascript/nodejs/nodejs-server-with-remote-config/) - [Configuration Hot-Reload](../../../examples/javascript/nodejs/nodejs-server-with-remote-config/) --- **VTEX Proprietary Software** - This library is proprietary to VTEX and licensed for internal use only.