NodeJS OTEL wrapper by Rebrandly
npm install rebrandly-otelOpenTelemetry SDK for Rebrandly Node.js services.
``bash`
npm install rebrandly-otel
| Variable | Required | Description |
|----------|----------|-------------|
| OTEL_SERVICE_NAME | Yes | Service identifier |OTEL_SERVICE_APPLICATION
| | Yes | Application namespace (groups services) |OTEL_EXPORTER_OTLP_ENDPOINT
| | Yes | OTLP collector endpoint |OTEL_REPO_NAME
| | No | Repository name |OTEL_COMMIT_ID
| | No | Commit ID for version tracking |
`javascript
const { lambdaHandler, logger } = require('rebrandly-otel');
exports.handler = lambdaHandler({ name: 'my-function' })(async (event) => {
logger.info('Processing', { eventId: event.id });
return { statusCode: 200 };
});
`
`javascript
const { awsMessageHandler } = require('rebrandly-otel');
const processRecord = awsMessageHandler({ name: 'process-message' })(async (record) => {
// trace context automatically extracted from message
return { success: true };
});
`
`javascript
const express = require('express');
const { otel, setupExpress } = require('rebrandly-otel');
const app = express();
setupExpress(otel, app);
app.get('/api/users', (req, res) => res.json({ users: [] }));
`
`javascript
const fastify = require('fastify')();
const { otel, setupFastify } = require('rebrandly-otel');
setupFastify(otel, fastify);
fastify.get('/api/users', async () => ({ users: [] }));
`
`javascript
const { otel } = require('rebrandly-otel');
await otel.span('operation-name', { 'user.id': userId }, async (span) => {
// your code
});
`
`javascript
const { logger } = require('rebrandly-otel');
logger.info('Order processed', { orderId, amount });
`
`javascript
const { fetchWithTracing } = require('rebrandly-otel');
const response = await fetchWithTracing('https://api.rebrandly.com/v1/links', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});
`
`javascript
const axios = require('axios');
const { axiosWithTracing } = require('rebrandly-otel');
const tracedAxios = axiosWithTracing(axios.create());
const response = await tracedAxios.get('https://api.rebrandly.com/v1/links');
`
`javascript
const { injectTraceparent } = require('rebrandly-otel');
const headers = { 'Content-Type': 'application/json' };
injectTraceparent(headers);
// headers now includes traceparent
`
`javascript
const { meter } = require('rebrandly-otel');
// Counter
const requestCounter = meter.meter.createCounter('http.requests.total', {
description: 'Total HTTP requests'
});
requestCounter.add(1, { method: 'GET', endpoint: '/api/users' });
// Histogram
const duration = meter.meter.createHistogram('http.request.duration', {
description: 'Request duration in ms',
unit: 'ms'
});
duration.record(123, { endpoint: '/api/users' });
// Gauge
const gauge = meter.meter.createGauge('queue.size', {
description: 'Current queue size'
});
gauge.record(42);
`
`javascript
const knex = require('knex');
const { instrumentKnex } = require('rebrandly-otel');
const db = knex({ client: 'postgresql', connection: { / config / } });
instrumentKnex(db);
// All queries now automatically traced
const users = await db('users').select('*');
`
`javascript
const { getAwsMessageAttributes } = require('rebrandly-otel');
await sqs.send(new SendMessageCommand({
QueueUrl: url,
MessageBody: JSON.stringify(data),
MessageAttributes: getAwsMessageAttributes()
}));
`
Use the awsMessageHandler wrapper (see AWS Message Handler above) - trace context is automatically extracted from message attributes.
`javascript
const { forceFlush, shutdown } = require('rebrandly-otel');
// Before Lambda exits
await forceFlush(5000);
await shutdown();
`
Standalone functions for setting span status (following Python SDK pattern):
`javascript
const { setSpanError, setSpanSuccess, setSpanUnset, getCurrentSpan } = require('rebrandly-otel');
// Set ERROR status on current span
setSpanError('Operation failed'); // String message
setSpanError(error); // Error object (records exception)
setSpanError('Failed', { exception: err }); // Message + exception
// Set ERROR on specific span
setSpanError('Failed', { span: mySpan });
setSpanError(error, { span: mySpan });
// Set OK status
setSpanSuccess(); // Current span
setSpanSuccess(mySpan); // Specific span
// Set UNSET status (neutral/default)
setSpanUnset(); // Current span
setSpanUnset(mySpan); // Specific span
`
`javascript
const { lambdaHandler, setSpanError } = require('rebrandly-otel');
exports.handler = lambdaHandler({ name: 'my-function' })(async (event) => {
try {
const result = await processOrder(event);
return { statusCode: 200, body: JSON.stringify(result) };
} catch (error) {
// Record error on current span
setSpanError(error);
throw error;
}
});
`
`javascript
const { otel, setSpanError, setSpanSuccess } = require('rebrandly-otel');
await otel.span('database-query', async (span) => {
try {
const result = await db.query('SELECT * FROM users');
setSpanSuccess(span); // Explicit success
return result;
} catch (error) {
setSpanError(error, { span }); // Record error on this span
throw error;
}
});
`
For high-volume services, filter out successful spans to reduce costs by 90-99%:
`bash`
export OTEL_SPAN_ATTRIBUTES="span.filter=errors-only"
This adds the filter attribute to all spans. The OTEL Gateway drops successful spans while keeping all errors. Metrics are still generated from 100% of traces at the agent level.
- Always call forceFlush() before Lambda exitsOTEL_DEBUG=true
- Use for local debugging
- Keep metric cardinality low (< 1000 combinations)
- Add 2-3 seconds buffer to Lambda timeout for flush
No Data Exported:
- Verify OTEL_EXPORTER_OTLP_ENDPOINT is setOTEL_DEBUG=true
- Enable for console output
- Check network connectivity to collector
Missing Traces in Lambda:
- Ensure forceFlush() is called before exitlambdaHandler
- Add 2-3s buffer to Lambda timeout
- Use with default auto-flush
Context Not Propagating:
- Sending: Use getAwsMessageAttributes() for SQS/SNSinjectTraceparent(headers)
- HTTP: Use before requestsawsMessageHandler
- Receiving: Use wrapper
Do:
- Use meaningful span names (fetch-user-profile, not handler)order.id
- Add business context (, user.id) to spans
- Flush telemetry before Lambda exits
- Use bounded attribute values in metrics
Don't:
- Store large payloads in span attributes (< 1KB)
- Use high-cardinality attributes in metrics (user_id, request_id)setSpanError(error)` to capture exceptions
- Hardcode service names (use env vars)
- Skip error recording in catch blocks - use