Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tracelit.io/llms.txt

Use this file to discover all available pages before exploring further.

Requirements: Node.js ≥ 18.0.0 · TypeScript ≥ 5 (optional) · CJS and ESM both supported

Installation

npm install @tracelit/sdk

Quick start

The SDK must be initialised before any other modules that need auto-instrumentation (Express, Mongoose, Redis, etc.). Create a dedicated init file and import it as the very first line of your entry point.
1

Create your Tracelit initializer

tracelit.ts
import Tracelit from "@tracelit/sdk";

Tracelit.configure((config) => {
  config.apiKey      = process.env.TRACELIT_API_KEY;   // required
  config.serviceName = "payments-api";                  // required
  config.environment = process.env.NODE_ENV ?? "production";
  config.sampleRate  = 1.0;
});

Tracelit.start();
2

Import the initializer first in your entry point

server.ts
import "./tracelit"; // ← MUST be the very first import

import express from "express";

const app = express();
app.get("/", (_req, res) => res.send("Hello, Tracelit!"));
app.listen(3000);
3

Set your environment variables

.env
TRACELIT_API_KEY=your-api-key
TRACELIT_SERVICE_NAME=payments-api
TRACELIT_ENVIRONMENT=production

Configuration reference

All options can be set in the configure callback or via environment variables.
OptionEnv variableDefaultDescription
apiKeyTRACELIT_API_KEYRequired. Your Tracelit ingest API key
serviceNameTRACELIT_SERVICE_NAMERequired. Service name shown in Tracelit
environmentTRACELIT_ENVIRONMENT"production"Deployment environment tag
endpointTRACELIT_ENDPOINThttps://ingest.tracelit.appOverride only when self-hosting
sampleRateTRACELIT_SAMPLE_RATE1.0Sampling ratio 0.01.0. Errors always export.
enabledTRACELIT_ENABLEDtrueSet false to disable all telemetry in tests
resourceAttributes{}Extra key/value pairs on every span, metric, and log

Custom resource attributes

Tracelit.configure((config) => {
  config.apiKey      = process.env.TRACELIT_API_KEY;
  config.serviceName = "orders-api";
  config.resourceAttributes = {
    "deployment.region": "us-east-1",
    "team": "platform",
  };
});

Tracing

Manual spans

Tracelit.tracer is a standard OpenTelemetry Tracer and supports the full OTel JS API.
import Tracelit from "@tracelit/sdk";

const result = await Tracelit.tracer.startActiveSpan("process_payment", async (span) => {
  span.setAttribute("payment.id", payment.id);
  span.setAttribute("payment.amount", String(amount));
  span.setAttribute("payment.currency", currency);

  try {
    const result = await processPayment(payment);
    span.setAttribute("payment.status", result.status);
    return result;
  } catch (err) {
    span.recordException(err as Error);
    span.setStatus({ code: 2 /* ERROR */, message: (err as Error).message });
    throw err;
  } finally {
    span.end();
  }
});

Automatic instrumentation

Tracelit.start() enables every auto-instrumentation package present in your node_modules via @opentelemetry/auto-instrumentations-node. No extra config needed.
LibraryWhat is captured
Express / Fastify / Koa / HapiHTTP request traces, route and method attributes
http / httpsAll inbound and outbound HTTP call traces
pg / mysql2 / better-sqlite3SQL query traces with sanitised statement text
Mongoose / MongoDBMongoDB operation traces
Redis / ioredisCache command traces
gRPCClient and server RPC traces
GraphQLResolver and query traces
Kafka.js / rheaMessage publish/consume traces
PrismaORM operation traces
Undici / fetchOutbound HTTP call traces

Metrics

Tracelit.metrics returns null before start() is called or when the SDK is disabled — optional chaining (?.) is safe everywhere.

Counter

const ordersPlaced = Tracelit.metrics.counter("orders.placed", {
  description: "Total orders placed",
  unit: "{orders}",
});

ordersPlaced?.add(1, { currency: "USD", channel: "web" });

Histogram

const apiLatency = Tracelit.metrics.histogram("external.api.duration", {
  description: "External API call duration",
  unit: "ms",
});

const start = Date.now();
await callExternalApi();
apiLatency?.record(Date.now() - start, { service: "stripe" });

Gauge

const queueDepth = Tracelit.metrics.gauge("job_queue.depth", {
  description: "Number of pending background jobs",
  unit: "{jobs}",
});

queueDepth?.record(await queue.pendingCount(), { queue: "default" });

Observable gauge (callback-based)

Use when the value is expensive to compute and should only be read on the export interval:
const queueGauge = Tracelit.metrics.observableGauge("message.queue.size", {
  description: "Estimated message queue size",
  unit: "{messages}",
});

queueGauge?.addCallback((result) => {
  result.observe(getQueueSize(), { queue: "events" });
});

HTTP server metrics (Express middleware)

import express from "express";
import Tracelit from "@tracelit/sdk";

const app = express();
app.use(Tracelit.expressMetricsMiddleware()); // ← add before routes
MetricTypeDescription
http.server.request.countCounterTotal HTTP requests
http.server.request.durationHistogramRequest duration (ms)
http.server.error.countCounter5xx responses
Attributes on all HTTP metrics: http.method, http.route, http.status_code.

Automatic process metrics

Once Tracelit.start() is called, the following are collected with no extra code:
MetricTypeDescriptionInterval
process.memory.rssGaugeProcess RSS memory (MB)60 s
process.event_loop.lagHistogramNode.js event loop lag (ms)30 s
Both pollers use unref()’d timers and will not prevent your process from exiting.

Logging

Console bridge (automatic)

When Tracelit.start() is called, all console.debug/log/info/warn/error calls are automatically forwarded to the OTel LoggerProvider. Original console output is preserved and logs are correlated with the active trace via trace_id and span_id.
console methodOTel SeverityNumber
debug / log5 (DEBUG)
info9 (INFO)
warn13 (WARN)
error17 (ERROR)

Winston transport

import winston from "winston";
import { WinstonTransport } from "@tracelit/sdk";
import { logs } from "@opentelemetry/api-logs";

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console(),
    new WinstonTransport(logs.getLoggerProvider()),
  ],
});

logger.info("Order created", { orderId: "ord_123" });

Pino destination

import pino from "pino";
import { createPinoDestination } from "@tracelit/sdk";
import { logs } from "@opentelemetry/api-logs";

const otelDest = createPinoDestination(logs.getLoggerProvider());

const logger = pino(
  pino.multistream([
    { stream: process.stdout },
    { stream: otelDest },
  ])
);

logger.info({ orderId: "ord_123" }, "Order created");

Sampling and error guarantee

Tracelit.configure((config) => {
  config.sampleRate = 0.1; // keep 10% of traces
});
Error spans are always exported, even when the parent trace is outside the sample ratio. The SDK uses ErrorAlwaysOnSampler + ErrorSpanProcessor to guarantee this — no configuration required.

Disabling in tests

// tracelit.ts
Tracelit.configure((config) => {
  config.apiKey      = process.env.TRACELIT_API_KEY;
  config.serviceName = "my-service";
  config.enabled     = process.env.TRACELIT_ENABLED !== "false";
});
Tracelit.start();
# Run tests with telemetry off
TRACELIT_ENABLED=false npx jest

# Or set permanently in .env.test
TRACELIT_ENABLED=false

TypeScript / JavaScript compatibility

The package ships as dual CJS + ESM bundles with full TypeScript declaration files.
import Tracelit from "@tracelit/sdk";

Tracelit.configure((c) => {
  c.apiKey      = process.env.TRACELIT_API_KEY;
  c.serviceName = "my-app";
});
Tracelit.start();

Complete example

import "./tracelit"; // initialise first!

import express from "express";
import Tracelit from "@tracelit/sdk";

const app = express();
app.use(Tracelit.expressMetricsMiddleware());

app.post("/orders", async (req, res) => {
  const result = await Tracelit.tracer.startActiveSpan("create-order", async (span) => {
    span.setAttribute("order.channel", req.body.channel ?? "web");

    try {
      const order = await createOrder(req.body);
      span.setAttribute("order.id", order.id);
      return order;
    } catch (err) {
      span.recordException(err as Error);
      span.setStatus({ code: 2, message: (err as Error).message });
      throw err;
    } finally {
      span.end();
    }
  });

  res.status(201).json(result);
});

app.listen(3000, () => console.log("Listening on :3000"));

GitHub

Source code and issue tracker: github.com/Tracelit-AI/tracelit-node