0.1.1 • Published 8 months ago

@auto-genesis/telemetry v0.1.1

Weekly downloads
-
License
-
Repository
-
Last release
8 months ago

Autonomize Telemetry (@auto-genesis/telemetry)

A lightweight, easy-to-use OpenTelemetry SDK for Node.js and Nest.js applications. This SDK provides unified instrumentation for traces, metrics, and logs with automatic context propagation and built-in support for popular frameworks.

Features

Metrics Collection

  • Track custom metrics with counters, histograms, and up/down counters
  • Configurable metric export intervals
  • Pre-configured metric attributes
  • Direct access to OpenTelemetry metrics API

Distributed Tracing

  • Automatic trace context propagation
  • Built-in span creation and management
  • Manual context propagation across services
  • Cross-language trace continuity (JavaScript/Python)
  • Custom attribute support
  • Support for error recording
  • Direct access to OpenTelemetry trace API

Structured Logging

  • Automatic trace correlation
  • Multiple severity levels (INFO, ERROR, WARN, DEBUG)
  • Custom attributes support
  • Error stack trace handling

Auto-Instrumentation

  • Initialization through env setup
  • No code changes required
  • HTTP client and server
  • Express.js framework
  • NestJS core components
  • Custom request hooks
  • Health check endpoint filtering

Installation

# Using npm
npm install @auto-genesis/telemetry

# Using yarn
yarn add @auto-genesis/telemetry

# Using pnpm
pnpm add @auto-genesis/telemetry

## Quick Start

### Auto-Instrumentation

The SDK supports automatic instrumentation of your Node.js application. To enable it:

1. Set the NODE_OPTIONS environment variable:

```bash
NODE_OPTIONS="--require @auto-genesis/telemetry/register"
  1. Configure your environment variables (see Configuration section)

  2. Start your application normally:

node app.js # you start script here

Manual Initialization

If you prefer manual control over the SDK initialization:

import { Telemetry } from '@auto-genesis/telemetry';

const telemetry = new Telemetry({
  serviceName: 'my-service',
  environment: 'production',
  version: '1.0.0',
  otlpEndpoint: 'http://otlpendpoint:3000',
});

await telemetry.start();

// Your application code here

// On shutdown
await telemetry.shutdown();

Configuration

TelemetryConfig Options

OptionTypeRequiredDefaultDescription
serviceNamestringYes-Unique identifier for your service
environmentstringYes-Deployment environment (e.g., 'production')
versionstringNoundefinedService version
otlpEndpointstringNo'http://localhost:4318'OpenTelemetry collector endpoint
metricIntervalMsnumberNo5000Metric export interval in milliseconds

Updated Configuration Options

Environment VariableDescriptionDefault ValueType
TELEMETRY_SERVICE_NAMEName of your service'unknown-service'string
TELEMETRY_SERVICE_VERSIONVersion of your service'0.0.0'string
TELEMETRY_ENVIRONMENTDeployment environment'development'string
TELEMETRY_EXPORTER_OTLP_ENDPOINTOpenTelemetry Collector endpoint'http://localhost:4318'string
TELEMETRY_HTTP_ENABLEDEnable HTTP instrumentationtrueboolean
TELEMETRY_EXPRESS_ENABLEDEnable Express instrumentationtrueboolean
TELEMETRY_NESTJS_ENABLEDEnable NestJS instrumentationfalseboolean
TELEMETRY_LOG_LEVELLog level (ERROR, WARN, INFO, DEBUG)'INFO'string
TELEMETRY_METRIC_EXPORT_INTERVALMetrics export interval in ms5000number

Example .env file

# Basic Service Configuration
TELEMETRY_SERVICE_NAME=my-service
TELEMETRY_SERVICE_VERSION=1.0.0
TELEMETRY_ENVIRONMENT=development

# OpenTelemetry Collector Endpoint
TELEMETRY_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

# Instrumentation Configuration
TELEMETRY_HTTP_ENABLED=true
TELEMETRY_EXPRESS_ENABLED=true
TELEMETRY_NESTJS_ENABLED=true

# Logging Configuration
TELEMETRY_LOG_LEVEL=INFO

# Metrics Configuration
TELEMETRY_METRIC_EXPORT_INTERVAL=5000

Usage Examples

Metrics (telemetry.metrics)

Metric TypeDescriptionUsage Example
CounterOnly increasestelemetry.metrics.createCounter(...)
HistogramDistribution of valuestelemetry.metrics.createHistogram(...)
UpDownCounterCan increase/decreasetelemetry.metrics.createUpDownCounter(...)

import { Telemetry } from '@auto-genesis/telemetry';

const telemetry = new Telemetry();

// Create counter
const requestCounter = telemetry.metrics.createCounter({
  name: 'http.requests.total',
  description: 'Total number of HTTP requests',
  unit: 'requests',
});

// Record metrics
requestCounter.add(1, { 'http.method': 'GET' });

// Create a histogram (distribution of values)
const histogram = telemetry.metrics.createHistogram({
  name: 'metric_name',
  description: 'metric description',
  unit: 'unit',
});

// Create an up/down counter (can increase/decrease)
const upDownCounter = telemetry.metrics.createUpDownCounter({
  name: 'metric_name',
  description: 'metric description',
  unit: 'unit',
});

// Access OpenTelemetry metrics API
const metricsAPI = telemetry.metrics.getMetrics();

Tracing (telemetry.tracing)

import { Telemetry } from '@auto-genesis/telemetry';

const telemetry = new Telemetry();

// Access OpenTelemetry trace API and context
const trace = telemetry.tracing.getTrace();
const context = telemetry.tracing.getContext();
const activeSpan = telemetry.tracing.getActiveSpan();

// Create a traced operation
await telemetry.tracing.createSpan('my-operation', async () => {
  // Your code here
  await doSomething();
});

// Add attributes to current span
telemetry.tracing.addAttributes({
  'custom.attribute': 'value',
});

// Record errors
try {
  await riskyOperation();
} catch (error) {
  telemetry.tracing.recordError(error);
  throw error;
}

// Manual context propagation across services
// Service A (sending trace context)
const traceCarrier = telemetry.tracing.injectCurrentContext();
// Send traceCarrier to Service B via HTTP, message queue, etc.

// Service B (receiving trace context)
const extractedContext = telemetry.tracing.extractContext(receivedCarrier);
await telemetry.tracing.createSpan(
  'service-b-operation',
  async () => {
    // This span will be connected to the trace from Service A
    await processRequest();
  },
  {
    context: extractedContext,
    attributes: { service: 'service-b' },
  },
);

Cross-Language Tracing Example

// JavaScript Service (sending to Python service)
// 1. Create a span and prepare context for transport
const traceCarrier = telemetry.tracing.injectCurrentContext();

// 2. Send request to Python service with context
const response = await axios.post('http://python-service/endpoint', {
  data: requestData,
  _traceContext: traceCarrier  // Include trace context in request
});

// Python Service (receiving from JavaScript)
"""
from opentelemetry import trace, context
from opentelemetry.propagate import extract

@app.route('/endpoint', methods=['POST'])
def handle_request():
    # 1. Extract trace context from request
    data = request.json
    carrier = data.get('_traceContext', {})
    ctx = extract(carrier)

    # 2. Create a span with the extracted context
    with tracer.start_as_current_span("process-request", context=ctx) as span:
        # This span will be connected to the JavaScript trace
        result = process_data(data['data'])

        # 3. When sending response, include context for continuation
        response_carrier = {}
        inject(response_carrier)
        return jsonify({
            'result': result,
            '_traceContext': response_carrier
        })
"""

// Back to JavaScript service (receiving response from Python)
// 3. Extract context from Python service response
const pythonContext = telemetry.tracing.extractContext(response.data._traceContext);

// 4. Continue the trace
await telemetry.tracing.createSpan('process-python-response', async () => {
  // This span will be connected to both previous spans
  processResult(response.data.result);
}, {
  context: pythonContext
});

Logging (telemetry.logging)

import { Telemetry } from '@auto-genesis/telemetry';

const telemetry = new Telemetry();

// Log with different levels
telemetry.logging.info('Operation successful', { operation: 'data-sync' });
telemetry.logging.error('Operation failed', new Error('Sync failed'));
telemetry.logging.debug('Debug information', { details: 'some debug data' });

NestJS Integration

import Telemetry from '@auto-genesis/telemetry';

async function bootstrap() {
  const telemetry = new Telemetry({
    serviceName: 'nest-service',
    environment: process.env.NODE_ENV,
  });

  await telemetry.start();

  const app = await NestFactory.create(AppModule);
  await telemetry.listen(3000);

  // Graceful shutdown
  process.on('SIGTERM', async () => {
    await telemetry.shutdown();
    await app.close();
  });
}

Context Propagation Interface

The SDK provides a standard interface for propagating trace context across service boundaries:

// Carrier interface for transporting trace context
interface TraceCarrier {
  traceparent?: string; // W3C Trace Context format
  tracestate?: string; // Additional trace state information
}

Playground

To test new features or debug locally:

  1. Clone the repository:

    git clone https://github.com/autonomize-ai/autonomize-sdk-js.git
    cd autonomize-sdk-js
  2. Set up the playground:

    cd playground
    cp .env.example .env   # Configure your environment variables
    pnpm install
  3. Run the OTel playground:

    pnpm dev:otel

This will start a development environment where you can test SDK features without publishing to npm.

Requirements

RequirementVersion
Node.js>= 14.x
OpenTelemetry CollectorLatest stable

Dependencies

PackageVersion
@opentelemetry/api^1.7.0
@opentelemetry/sdk-node^0.54.1
@opentelemetry/auto-instrumentations-node^0.52.0
@opentelemetry/instrumentation-nestjs-core^0.41.0

See package.json for the complete list of dependencies.

Additional Resources