npm package: @jaymanyoo/microservices-tracing
Description: A simple OpenTelemetry tracing setup for Node.js microservices
Author: jaymanyoo
Latest version: 1.1.0

# Microservice Tracing

A simple, configurable OpenTelemetry tracing package for Node.js microservices with Jaeger integration.

## Features

- 🚀 **Zero-config setup** - Works out of the box with sensible defaults
- 🔧 **Highly configurable** - Customize instrumentations, endpoints, and behavior
- 🏗️ **Framework agnostic** - Works with Express, Fastify, and other Node.js frameworks
- 📊 **Auto-instrumentation** - Automatically traces HTTP, databases, message queues, and more
- 🐳 **Container-friendly** - Designed for containerized microservices
- ⚡ **Minimal overhead** - Optimized for production use

## Quick Start

### Installation

```bash
npm install microservice-tracing
```

### Basic Usage

```typescript
// Import at the very top of your main file, before any other imports
import { initializeTracing } from 'microservice-tracing';

// Initialize tracing
initializeTracing({
  serviceName: 'my-service'
});

// Now import and start your application
import express from 'express';
// ... rest of your application
```

### Advanced Configuration

```typescript
import { initializeTracing } from 'microservice-tracing';

initializeTracing({
  serviceName: 'my-service',
  serviceVersion: '1.2.3',
  environment: 'production',
  jaegerEndpoint: 'http://jaeger-collector:14268/api/traces',
  ignoreUrls: ['/health', '/metrics', '/custom-ignore'],
  instrumentations: {
    http: true,
    express: true,
    mysql: true,
    redis: true,
    amqp: true,
    socketio: false, // Disable if not using Socket.IO
    fs: false,       // Disabled by default (noisy)
    dns: false       // Disabled by default (noisy)
  }
});
```

## Configuration Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `serviceName` | `string` | **Required** | Name of your service as it appears in Jaeger |
| `serviceVersion` | `string` | `process.env.SERVICE_VERSION \|\| '1.0.0'` | Version of your service |
| `environment` | `string` | `process.env.NODE_ENV \|\| 'development'` | Deployment environment |
| `jaegerEndpoint` | `string` | `process.env.JAEGER_ENDPOINT \|\| 'http://jaeger:14268/api/traces'` | Jaeger collector endpoint |
| `disabled` | `boolean` | `process.env.OTEL_DISABLED === 'true'` | Disable tracing entirely |
| `ignoreUrls` | `string[]` | `['/health', '/ping', '/favicon', '/metrics']` | URLs to ignore in HTTP tracing |
| `instrumentations` | `object` | See below | Enable/disable specific instrumentations |

### Instrumentation Options

```typescript
instrumentations: {
  http: boolean;      // HTTP client/server (default: true)
  express: boolean;   // Express.js framework (default: true)
  mysql: boolean;     // MySQL/MySQL2 database (default: true)
  redis: boolean;     // Redis client (default: true)
  amqp: boolean;      // RabbitMQ/AMQP (default: true)
  socketio: boolean;  // Socket.IO (default: false)
  fs: boolean;        // File system operations (default: false)
  dns: boolean;       // DNS lookups (default: false)
}
```

## Environment Variables

You can configure the package using environment variables:

```bash
# Disable tracing entirely
OTEL_DISABLED=true

# Set Jaeger endpoint
JAEGER_ENDPOINT=http://jaeger-collector:14268/api/traces

# Set service version
SERVICE_VERSION=1.2.3

# Set environment
NODE_ENV=production
```

## Usage Patterns

### Express.js Application

```typescript
// src/index.ts
import { initializeTracing } from 'microservice-tracing';

// Initialize tracing first
initializeTracing({
  serviceName: 'user-service',
  instrumentations: {
    express: true,
    mysql: true,
    redis: true
  }
});

// Then import your application
import express from 'express';
import { createUserRoutes } from './routes/users';

const app = express();
app.use('/users', createUserRoutes());

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
```

### With Database and Redis

```typescript
import { initializeTracing } from 'microservice-tracing';

initializeTracing({
  serviceName: 'data-service',
  instrumentations: {
    mysql: true,    // Traces MySQL queries
    redis: true,    // Traces Redis operations
    amqp: true      // Traces RabbitMQ messages
  }
});

// Your database and Redis operations will be automatically traced
import mysql from 'mysql2/promise';
import redis from 'redis';
```

### Chat Service with Socket.IO

```typescript
import { initializeTracing } from 'microservice-tracing';

initializeTracing({
  serviceName: 'chat-service',
  instrumentations: {
    socketio: true,  // Enable Socket.IO tracing
    mysql: true,
    redis: true
  }
});

import { Server } from 'socket.io';
// Socket.IO events will be automatically traced
```

### Microservice with Message Queues

```typescript
import { initializeTracing } from 'microservice-tracing';

initializeTracing({
  serviceName: 'notification-service',
  instrumentations: {
    amqp: true,     // Traces RabbitMQ publish/consume
    http: true      // Traces outgoing HTTP calls
  }
});

// RabbitMQ operations will be automatically traced
import amqp from 'amqplib';
```

## Manual Instrumentation

For custom spans and metrics:

```typescript
import { trace } from 'microservice-tracing';

const tracer = trace.getTracer('my-service');

async function processOrder(orderId: string) {
  const span = tracer.startSpan('process-order');
  
  try {
    span.setAttributes({
      'order.id': orderId,
      'operation.type': 'business-logic'
    });
    
    // Your business logic here
    const result = await performOrderProcessing(orderId);
    
    span.setStatus({ code: 1 }); // OK
    return result;
  } catch (error) {
    span.recordException(error);
    span.setStatus({ code: 2, message: error.message }); // ERROR
    throw error;
  } finally {
    span.end();
  }
}
```

## Production Considerations

### Performance

The package is optimized for production use with minimal overhead (~1-3%). Key optimizations:

- File system and DNS instrumentations are disabled by default
- Health check endpoints are ignored
- Efficient batch export to Jaeger

### Sampling

For high-traffic services, you may want to implement sampling:

```typescript
// Set sampling rate via environment variable
process.env.OTEL_TRACES_SAMPLER = 'traceidratio';
process.env.OTEL_TRACES_SAMPLER_ARG = '0.1'; // Sample 10% of traces

initializeTracing({
  serviceName: 'high-traffic-service'
});
```

### Security

- The package doesn't expose any sensitive information
- All configuration is done via environment variables or explicit config
- No sensitive data is automatically captured in spans

### Container Deployment

```dockerfile
# Dockerfile
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .

# Set tracing environment variables
ENV JAEGER_ENDPOINT=http://jaeger-collector:14268/api/traces
ENV SERVICE_VERSION=1.0.0

CMD ["node", "dist/index.js"]
```

```yaml
# docker-compose.yml or Kubernetes deployment
environment:
  - JAEGER_ENDPOINT=http://jaeger-collector:14268/api/traces
  - SERVICE_VERSION=1.0.0
  - NODE_ENV=production
```

## Troubleshooting

### Common Issues

1. **No traces appearing in Jaeger**
   - Check that Jaeger is running and accessible
   - Verify the `JAEGER_ENDPOINT` is correct
   - Look for initialization logs in your service

2. **High memory usage**
   - Disable file system instrumentation (default)
   - Implement sampling for high-traffic services
   - Check for memory leaks in your application code

3. **Missing spans**
   - Ensure tracing is initialized before importing other modules
   - Check that the relevant instrumentation is enabled
   - Verify the operation is supported by auto-instrumentation

### Debug Mode

Enable debug logging:

```bash
DEBUG=@opentelemetry/* node your-app.js
```

### Health Checks

The package automatically ignores common health check endpoints. To verify tracing is working:

```bash
# This will be traced
curl http://your-service/api/users

# This will be ignored
curl http://your-service/health
```

## API Reference

### `initializeTracing(config: TracingConfig): MicroserviceTracing`

Convenience function that creates, initializes, and sets up graceful shutdown for tracing.

### `class MicroserviceTracing`

#### `constructor(config: TracingConfig)`

Creates a new tracing instance.

#### `initialize(): void`

Initializes OpenTelemetry tracing.

#### `shutdown(): Promise<void>`

Gracefully shuts down tracing.

#### `setupGracefulShutdown(): void`

Sets up process signal handlers for graceful shutdown.

## License

MIT