# @vtex/diagnostics-nodejs

> Diagnostics library for Node.js applications

Latest version **5.5.3** (published 2026-08-21) · ISC license · 0 weekly downloads

## Install

```sh
npm install @vtex/diagnostics-nodejs
pnpm add @vtex/diagnostics-nodejs
yarn add @vtex/diagnostics-nodejs
bun add @vtex/diagnostics-nodejs
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 5.5.3 |
| Published | 2026-08-21 |
| First published | 2025-03-19 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=14.0.0 |
| Dependencies | 26 |
| Unpacked size | 353.4 KB |
| Known vulnerabilities | 0 (+1 in 1 direct dependencies) |
| Install scripts | no |
| Author | SRE Observability Team |
| Maintainers | eduardoformiga, natamelo, rafarubim, victorhmp, lurian, arturpimentel, emersonlaurentino, viniagostini, lucasaarcoverde, lariciamota, geraldo.fernandes, mateuspontes, vitorlgomes, marcelovicentegc, maianabt, hiagolcm, wender, mendescamara, thiago.pereira.vtex, kevinvtex, myllena.alves, enzomerca, jardelymaris, daniyelnnr, denissilvavtex, vinhags, georgebrindeiro, marcos_vtex, laisribeiro, lucasfp13-vtex, brunoamui, fdaciuk_vtex, sophreisvtex, sagginvtex, williamcunhavtex, amandascmvtex, gabriel_bozelli, thaynannunes, vtexlab-user, yasminteles, guieevc-vtex, evertonstrack, arthurtriis1vtex, mmartinsoliv, rerissonvtex, ernestosbarbosa, wisney.cardeal, gabriellymoura, mpcardoso, rafael.pereira, amilton.vtex, orem, luis.mafra, luis.mollmann, leidymgdev, guilhermeribeiro30 |
| Keywords | vtex, diagnostics, opentelemetry, telemetry, observability |

## Links

- npm: https://www.npmjs.com/package/@vtex/diagnostics-nodejs
- Repository: https://github.com/vtex/diagnostics
- Homepage: https://github.com/vtex/diagnostics#readme
- Issues: https://github.com/vtex/diagnostics/issues
- npm.io page: https://npm.io/package/@vtex/diagnostics-nodejs

## Dependencies (26)

- [uuid](https://npm.io/package/uuid.md) ^11.1.0
- [tslib](https://npm.io/package/tslib.md) ^2.8.1
- [@grpc/grpc-js](https://npm.io/package/@grpc/grpc-js.md) ^1.13.4
- [@aws-sdk/client-s3](https://npm.io/package/@aws-sdk/client-s3.md) ^3.848.0
- [@opentelemetry/api](https://npm.io/package/@opentelemetry/api.md) ^1.9.0
- [@opentelemetry/core](https://npm.io/package/@opentelemetry/core.md) ^2.0.0
- [@opentelemetry/api-logs](https://npm.io/package/@opentelemetry/api-logs.md) ^0.200.0
- [@opentelemetry/sdk-logs](https://npm.io/package/@opentelemetry/sdk-logs.md) ^0.200.0
- [@opentelemetry/sdk-node](https://npm.io/package/@opentelemetry/sdk-node.md) ^0.200.0
- [@opentelemetry/resources](https://npm.io/package/@opentelemetry/resources.md) ^2.0.0
- [@vtex/diagnostics-semconv](https://npm.io/package/@vtex/diagnostics-semconv.md) 5.5.3
- [@opentelemetry/sdk-metrics](https://npm.io/package/@opentelemetry/sdk-metrics.md) ^2.0.0
- [@opentelemetry/sdk-trace-base](https://npm.io/package/@opentelemetry/sdk-trace-base.md) ^2.0.0
- [@opentelemetry/sdk-trace-node](https://npm.io/package/@opentelemetry/sdk-trace-node.md) ^2.0.0
- [@opentelemetry/instrumentation](https://npm.io/package/@opentelemetry/instrumentation.md) ^0.200.0
- [@opentelemetry/context-async-hooks](https://npm.io/package/@opentelemetry/context-async-hooks.md) ^2.0.1
- [@opentelemetry/instrumentation-net](https://npm.io/package/@opentelemetry/instrumentation-net.md) ^0.44.0
- [@opentelemetry/instrumentation-http](https://npm.io/package/@opentelemetry/instrumentation-http.md) ^0.200.0
- [@opentelemetry/semantic-conventions](https://npm.io/package/@opentelemetry/semantic-conventions.md) ^1.30.0
- [@opentelemetry/resource-detector-aws](https://npm.io/package/@opentelemetry/resource-detector-aws.md) ^1.12.0
- [@opentelemetry/baggage-span-processor](https://npm.io/package/@opentelemetry/baggage-span-processor.md) ^0.4.0
- [@opentelemetry/exporter-logs-otlp-grpc](https://npm.io/package/@opentelemetry/exporter-logs-otlp-grpc.md) ^0.200.0
- [@opentelemetry/instrumentation-express](https://npm.io/package/@opentelemetry/instrumentation-express.md) ^0.47.1
- [@opentelemetry/exporter-trace-otlp-grpc](https://npm.io/package/@opentelemetry/exporter-trace-otlp-grpc.md) ^0.200.0
- [@opentelemetry/exporter-metrics-otlp-grpc](https://npm.io/package/@opentelemetry/exporter-metrics-otlp-grpc.md) ^0.200.0
- [@opentelemetry/instrumentation-runtime-node](https://npm.io/package/@opentelemetry/instrumentation-runtime-node.md) ^0.14.0

## Recent versions

- 5.5.3 (latest) — 2026-08-21
- 0.1.8-io-beta.0 (io-beta) — 2026-02-04
- 0.1.8-io (io) — 2025-12-16
- 0.1.0-io-beta.26 (beta) — 2025-12-12
- 0.1.0-io-beta.23 (@vtex/diagnostics-nodejs@0.1.0-io-beta.23) — 2025-12-10
- 5.5.2 — 2026-07-29
- 0.1.8-beta.3 — 2026-02-03
- 0.1.7-io — 2025-12-16
- 0.1.0-io-beta.25 — 2025-12-12
- 0.1.0-io-beta.24 — 2025-12-11
- 5.1.1 — 2025-10-16
- 5.1.0 — 2025-10-07
- 5.0.0 — 2025-09-30
- 0.1.0-io-beta.20 — 2025-09-02
- 1.1.2 — 2025-08-14
- … 21 more at https://npm.io/package/@vtex/diagnostics-nodejs/versions

## README

# 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
- **Structured Events**: Send structured, severity-less logs for event tracking.
- **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

This library is hosted on a private AWS CodeArtifact registry. To install it, follow these steps:

### 1. Configure the Scoped Registry

Create or update an `.npmrc` file in your project root:

```plaintext
@vtex:registry=https://main-053131491888.d.codeartifact.us-east-1.amazonaws.com/npm/observability/
//main-053131491888.d.codeartifact.us-east-1.amazonaws.com/npm/observability/:always-auth=true
//main-053131491888.d.codeartifact.us-east-1.amazonaws.com/npm/observability/:_authToken=${CODEARTIFACT_AUTH_TOKEN}
```

### 2. Authenticate with AWS

You need a valid authorization token from AWS CodeArtifact. Run the following command (requires [AWS CLI](https://aws.amazon.com/cli/) configured):

```bash
# Get the token
export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain main --domain-owner 053131491888 --region us-east-1 --query authorizationToken --output text)
```

> **Note:** Authorization tokens are valid for 12 hours.

### 3. Install the library

```bash
pnpm 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();
  const eventsClient = await telemetryClient.newEventsClient();

  // 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 });
    eventsClient.event('api.users.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
```

### Runtime Metrics

Node.js runtime metrics (event loop utilization/delay, GC duration, heap space usage) are collected automatically via `@opentelemetry/instrumentation-runtime-node` — no configuration required, no opt-out.

## 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();
```

## Structured Events

The library supports sending structured events, which are essentially logs without a severity level, ideal for capturing business or system events for analysis.

### Emitting Events

To send events, you first need to create an `EventsClient`. This client requires a gRPC exporter to be configured.

```javascript
// In your telemetry setup
const eventsClient = await telemetryClient.newEventsClient();

// In your application logic
app.post('/api/users', (req, res) => {
  // ... user creation logic ...

  eventsClient.event('user.created', {
    'user.id': newUser.id,
    'user.name': newUser.name,
    'request.id': req.id,
  });

  res.status(201).json(newUser);
});
```

### Configuration for Events

The `EventsClient` exclusively uses the OTLP gRPC exporter. You must configure the OTLP endpoint for logs in your configuration file for the `newEventsClient()` method to succeed.

```json
// config/telemetry.json
{
  "logs": {
    "exporters": {
      "mode": "otlp",
      "otlp": {
        "endpoint": "otel-collector:4317"
      }
    }
  }
}
```

If the OTLP exporter is not configured, `newEventsClient()` will throw an error.

## 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" }
          ]
        }
      ]
    }
  }
}
```

## Available Guides

For more information and detailed setup instructions, see our guides:

- **[Collector URLs](./docs/collector-urls.md)**: Standard gRPC endpoints for VTEX's OpenTelemetry Collector journeys.
- **[Multi-Pipeline Metrics Clients](./docs/multi-pipeline-metrics.md)**: System, Delta, and Business metric pipelines — client selection and export intervals.
- **[Semantic Conventions](./docs/semantic-conventions.md)**: Standardized naming for observability signals.
- **[Log Sampling](./docs/log-sampling.md)**: Control log volume at the source with dynamic sampling.
- **[GitHub Actions Configuration](./docs/github-actions.md)**: Detailed instructions on how to authenticate with AWS CodeArtifact and install the library in CI/CD environments.
- **[Attribute Enrichment Strategy](./docs/attribute-enrichment-strategy.md)**: How to choose between Resource Attributes, `baseAttributes`, and `withContext` for log enrichment.
- **[Database and Cache Auto-Instrumentation](./docs/database-instrumentation.md)**: Wire up OTel contrib instrumentations (Postgres, Redis, DynamoDB, OpenSearch/Elasticsearch) via `instrumentations`.

## 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/)

## Version Policy

This library follows [Semantic Versioning](https://semver.org/). The current version is in `package.json`.

| Tag pattern | Trigger |
|---|---|
| `js-nodejs-v<semver>` | dkcicd publishes `@vtex/diagnostics-nodejs` to AWS CodeArtifact npm registry |

To bump the version:
```bash
cd libs/javascript
make bump-patch   # bug fix
make bump-minor   # new feature (backwards-compatible)
make bump-major   # breaking change
```

Always run `make test-all` from the repo root before bumping. Never hand-edit `semconv/` generated output — use `make semconv-generate TAG=<version>` instead.

## Contributing

See [CONTRIBUTING.md](../../../CONTRIBUTING.md) for the full workflow, including adding semantic convention attributes and bumping versions.

---

**VTEX Proprietary Software** - This library is proprietary to VTEX and licensed for internal use only.

---
_Source: https://npm.io/package/@vtex/diagnostics-nodejs · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
