Skip to content
reaatechREAATECH

@reaatech/otel-genai-semconv-observability

npm v0.1.0

Provides pre-configured OpenTelemetry SDK initialization, Pino-based structured logging, and GenAI-specific metrics instrumentation for LLM applications. It exports utility functions to bootstrap observability, manage trace exporters, and expose health check endpoints.

@reaatech/otel-genai-semconv-observability

npm version License: MIT CI

Status: Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.

Structured logging, OpenTelemetry SDK setup, metrics instrumentation, and health checks for GenAI workloads. Built on Pino (v10) and the OpenTelemetry JS SDK, providing a zero-config path to production observability for LLM applications.

Installation

terminal
npm install @reaatech/otel-genai-semconv-observability
# or
pnpm add @reaatech/otel-genai-semconv-observability

Feature Overview

  • Structured JSON logging — Pino-powered with automatic pretty-printing in development
  • OpenTelemetry SDK bootstrap — one-call initialization with OTLP trace export
  • GenAI metrics — pre-built counters and histograms for requests, tokens, cost, errors, and TTFT
  • Runtime health checks — OTel SDK health, memory threshold monitoring, exporter connectivity
  • HTTP health endpoint — pluggable handler for Kubernetes/Docker health probes
  • Dual ESM/CJS output — works with import and require

Quick Start

typescript
import { initOTelSDK, createLogger, initMetrics } from "@reaatech/otel-genai-semconv-observability";
 
// Start the OTel SDK with OTLP export
const sdk = initOTelSDK({ serviceName: "my-llm-app" });
await sdk.start();
 
// Create a structured logger
const logger = createLogger({ level: "info" });
logger.info({ provider: "openai", model: "gpt-4" }, "LLM request started");
 
// Set up metrics
const meterProvider = initMetrics({ serviceName: "my-llm-app" });

API Reference

OpenTelemetry SDK Setup

initOTelSDK(config?): NodeSDK

Creates a configured NodeSDK instance with OTLP trace export. Does not start the SDK — call sdk.start() after creation.

typescript
const sdk = initOTelSDK({
  serviceName: "my-service",
  serviceVersion: "1.0.0",
  otlpEndpoint: "http://localhost:4318/v1/traces",
  additionalResources: { "deployment.environment": "production" },
});

OTelConfig

PropertyTypeDefaultDescription
serviceNamestringotel-genai-semconvService name for resource attributes
serviceVersionstring1.0.0Service version
otlpEndpointstringenv.OTEL_EXPORTER_OTLP_ENDPOINT or localhost:4318OTLP HTTP trace endpoint
additionalResourcesRecord<string, string>Additional OTel resource attributes

startOTelSDK(config?): Promise<NodeSDK>

Creates and starts the SDK in one call. Returns the running SDK instance.

shutdownOTelSDK(sdk: NodeSDK): Promise<void>

Gracefully shuts down the SDK, flushing pending spans and metrics.

Logging

createLogger(config?): Logger

Creates a configured Pino logger instance.

typescript
const logger = createLogger({
  level: "debug",
  prettyPrint: true,
  serviceName: "my-llm-app",
});

LoggerConfig

PropertyTypeDefaultDescription
levelstringenv.LOG_LEVEL or infoMinimum log level (trace, debug, info, warn, error, fatal)
prettyPrintbooleanNODE_ENV !== "production"Enable pino-pretty for human-readable output
serviceNamestringotel-genai-semconvService name in log context

logGenAIEvent(logger, level, message, context?)

Log a GenAI event with structured context:

typescript
logGenAIEvent(logger, "info", "LLM request completed", {
  provider: "openai",
  model: "gpt-4",
  inputTokens: 50,
  outputTokens: 100,
  costUsd: 0.0045,
  durationMs: 1234,
  traceId: span.spanContext().traceId,
});

LogContext

PropertyTypeDescription
traceIdstringOTel trace ID
spanIdstringOTel span ID
providerstringLLM provider name
modelstringModel name
inputTokensnumberInput token count
outputTokensnumberOutput token count
costUsdnumberCost in USD
durationMsnumberRequest duration in ms
errorstringError message

Metrics

initMetrics(config?): MeterProvider

Creates a MeterProvider with periodic console export.

createGenAIMeter(meterProvider): GenAIMeter

Creates pre-configured metric instruments:

InstrumentTypeNameDescription
requestsTotalCountergenai.requests.totalTotal LLM requests
requestDurationHistogramgenai.request.duration_msRequest latency in ms
tokensInputCountergenai.tokens.inputInput tokens consumed
tokensOutputCountergenai.tokens.outputOutput tokens generated
costTotalHistogramgenai.cost.totalCost per request in USD
errorsTotalCountergenai.errors.totalTotal errors
streamingTTFTHistogramgenai.streaming.time_to_first_token_msTime to first token in ms

Health Checks

performHealthCheck(config?): Promise<HealthCheckResult>

Runs a health check and returns a structured result:

typescript
const result = await performHealthCheck({ memoryThresholdMB: 512 });
// { healthy: true, components: { otelSDK: { healthy: true }, memory: { healthy: true, ... } }, timestamp: "..." }

HealthCheckConfig

PropertyTypeDefaultDescription
checkOTelSDKbooleantrueVerify OTel tracer is operational
checkExporterConnectivitybooleanfalseVerify exporter connectivity
memoryThresholdMBnumber512Heap threshold for memory health

createHealthCheckHandler(config?)

Returns an HTTP handler suitable for Express/Hono health endpoints. Returns 200 when healthy, 503 when unhealthy.

Usage Patterns

Structured Context Logging

typescript
const logger = createLogger({ serviceName: "llm-gateway" });
 
logger.info({
  provider: "openai",
  model: "gpt-4",
  requestId: "req-abc123",
}, "Processing completion request");

Error Logging

typescript
try {
  await client.chat.completions.create(params);
} catch (err) {
  logger.error({ err, provider: "openai" }, "LLM request failed");
}

Production vs Development

The logger automatically switches behavior:

  • Development (NODE_ENV !== "production"): colorized, human-readable output via pino-pretty
  • Production (NODE_ENV === "production"): raw JSON for log aggregators (Datadog, CloudWatch, ELK)

License

MIT