rebrandly-otel
v0.4.19
Published
NodeJS OTEL wrapper by Rebrandly
Downloads
1,459
Readme
rebrandly-otel (Node.js)
OpenTelemetry SDK for Rebrandly Node.js services.
Installation
npm install rebrandly-otelEnvironment Variables
| 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 |
Lambda Handler
const { lambdaHandler, logger } = require('rebrandly-otel');
exports.handler = lambdaHandler({ name: 'my-function' })(async (event) => {
logger.info('Processing', { eventId: event.id });
return { statusCode: 200 };
});AWS Message Handler
const { awsMessageHandler } = require('rebrandly-otel');
const processRecord = awsMessageHandler({ name: 'process-message' })(async (record) => {
// trace context automatically extracted from message
return { success: true };
});Framework Middleware
Express
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: [] }));Fastify
const fastify = require('fastify')();
const { otel, setupFastify } = require('rebrandly-otel');
setupFastify(otel, fastify);
fastify.get('/api/users', async () => ({ users: [] }));Custom Instrumentation
Manual Spans
const { otel } = require('rebrandly-otel');
await otel.span('operation-name', { 'user.id': userId }, async (span) => {
// your code
});Structured Logging
const { logger } = require('rebrandly-otel');
logger.info('Order processed', { orderId, amount });HTTP Client Tracing
Using fetch
const { fetchWithTracing } = require('rebrandly-otel');
const response = await fetchWithTracing('https://api.rebrandly.com/v1/links', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});Using axios
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');Manual Header Injection
const { injectTraceparent } = require('rebrandly-otel');
const headers = { 'Content-Type': 'application/json' };
injectTraceparent(headers);
// headers now includes traceparentCustom Metrics
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);Database Instrumentation
Knex.js
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('*');AWS Message Handling (SQS/SNS)
Sending with Trace Context
const { getAwsMessageAttributes } = require('rebrandly-otel');
await sqs.send(new SendMessageCommand({
QueueUrl: url,
MessageBody: JSON.stringify(data),
MessageAttributes: getAwsMessageAttributes()
}));Receiving with Context Extraction
Use the awsMessageHandler wrapper (see AWS Message Handler above) - trace context is automatically extracted from message attributes.
Force Flush (Critical for Lambda)
const { forceFlush, shutdown } = require('rebrandly-otel');
// Before Lambda exits
await forceFlush(5000);
await shutdown();Span Status Convenience Functions
Standalone functions for setting span status (following Python SDK pattern):
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 spanUsage in Error Handling
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;
}
});Usage with Custom Spans
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;
}
});Cost Optimization (Errors-Only Filtering)
For high-volume services, filter out successful spans to reduce costs by 90-99%:
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.
Tips
- Always call
forceFlush()before Lambda exits - Use
OTEL_DEBUG=truefor local debugging - Keep metric cardinality low (< 1000 combinations)
- Add 2-3 seconds buffer to Lambda timeout for flush
Troubleshooting
No Data Exported:
- Verify
OTEL_EXPORTER_OTLP_ENDPOINTis set - Enable
OTEL_DEBUG=truefor console output - Check network connectivity to collector
Missing Traces in Lambda:
- Ensure
forceFlush()is called before exit - Add 2-3s buffer to Lambda timeout
- Use
lambdaHandlerwith default auto-flush
Context Not Propagating:
- Sending: Use
getAwsMessageAttributes()for SQS/SNS - HTTP: Use
injectTraceparent(headers)before requests - Receiving: Use
awsMessageHandlerwrapper
Best Practices
Do:
- Use meaningful span names (
fetch-user-profile, nothandler) - Add business context (
order.id,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) - Hardcode service names (use env vars)
- Skip error recording in catch blocks - use
setSpanError(error)to capture exceptions
