A lightweight wrapper around OpenTelemetry for Node.js applications that simplifies sending traces to Arize Phoenix. This package provides an easy-to-use register function that handles all the boilerplate configuration for OpenTelemetry tracing.
Note: This package is under active development and APIs may change.
npm install @arizeai/phoenix-otel
The simplest way to get started is to use the register function:
import { register } from "@arizeai/phoenix-otel";
// Register with default settings (connects to localhost:6006)
register({
projectName: "my-app",
});
For production use with Phoenix Cloud:
import { register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app",
url: "https://app.phoenix.arize.com",
apiKey: process.env.PHOENIX_API_KEY,
});
The register function automatically reads from environment variables:
# For local Phoenix server (default)
export PHOENIX_COLLECTOR_ENDPOINT="http://localhost:6006"
# For Phoenix Cloud
export PHOENIX_COLLECTOR_ENDPOINT="https://app.phoenix.arize.com"
export PHOENIX_API_KEY="your-api-key"
The register function accepts the following parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
projectName |
string |
"default" |
The project name for organizing traces in Phoenix |
url |
string |
"http://localhost:6006" |
The URL to your Phoenix instance |
apiKey |
string |
undefined |
API key for Phoenix authentication |
headers |
Record<string, string> |
{} |
Custom headers for OTLP requests |
batch |
boolean |
true |
Use batch span processing (recommended for production) |
instrumentations |
Instrumentation[] |
undefined |
Array of OpenTelemetry instrumentations to register |
global |
boolean |
true |
Register the tracer provider globally |
diagLogLevel |
DiagLogLevel |
undefined |
Diagnostic logging level for debugging |
Automatically instrument common libraries (works best with CommonJS):
import { register } from "@arizeai/phoenix-otel";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
register({
projectName: "my-express-app",
instrumentations: [new HttpInstrumentation(), new ExpressInstrumentation()],
});
Note: Auto-instrumentation via the
instrumentationsparameter works best with CommonJS projects. ESM projects require manual instrumentation.
For ESM projects, manually instrument libraries:
// instrumentation.ts
import { register, registerInstrumentations } from "@arizeai/phoenix-otel";
import OpenAI from "openai";
import { OpenAIInstrumentation } from "@arizeai/openinference-instrumentation-openai";
register({
projectName: "openai-app",
});
// Manual instrumentation for ESM
const instrumentation = new OpenAIInstrumentation();
instrumentation.manuallyInstrument(OpenAI);
registerInstrumentations({
instrumentations: [instrumentation],
});
// main.ts
import "./instrumentation.ts";
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello!" }],
});
Create custom spans using the OpenTelemetry API:
import { register, trace } from "@arizeai/phoenix-otel";
register({ projectName: "my-app" });
const tracer = trace.getTracer("my-service");
async function processOrder(orderId: string) {
return tracer.startActiveSpan("process-order", async (span) => {
try {
span.setAttribute("order.id", orderId);
// Your business logic here
const result = await fetchOrderDetails(orderId);
span.setAttribute("order.status", result.status);
return result;
} catch (error) {
span.recordException(error as Error);
span.setStatus({ code: SpanStatusCode.ERROR });
throw error;
} finally {
span.end();
}
});
}
Development (with debug logging):
import { register } from "@arizeai/phoenix-otel";
import { DiagLogLevel } from "@opentelemetry/api";
register({
projectName: "my-app-dev",
url: "http://localhost:6006",
batch: false, // Immediate span delivery for faster feedback
diagLogLevel: DiagLogLevel.DEBUG,
});
Production (optimized for performance):
import { register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app-prod",
url: "https://app.phoenix.arize.com",
apiKey: process.env.PHOENIX_API_KEY,
batch: true, // Batch processing for better performance
});
Add custom headers to OTLP requests:
import { register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app",
url: "https://app.phoenix.arize.com",
headers: {
"X-Custom-Header": "custom-value",
"X-Environment": process.env.NODE_ENV || "development",
},
});
Use the provider explicitly without registering globally:
import { register } from "@arizeai/phoenix-otel";
const provider = register({
projectName: "my-app",
global: false,
});
// Use the provider explicitly
const tracer = provider.getTracer("my-tracer");
For convenience, commonly used OpenTelemetry APIs are re-exported:
import {
trace, // Main tracing API
context, // Context API
SpanStatusCode, // Span status codes
registerInstrumentations, // Register instrumentations
type DiagLogLevel, // Diagnostic log levels
type Tracer, // Tracer type
type Instrumentation, // Instrumentation type
type NodeTracerProvider, // Provider type
} from "@arizeai/phoenix-otel";
Join our community to connect with thousands of AI builders: