A simple wrapper around OpenTelemetry for use with Arize Phoenix. This package simplifies the setup of OpenTelemetry tracing for Node.js applications, providing an easy way to send traces to Phoenix for observability and analysis.
Note: This package is still under active development and is subject to change.
Installation
npm install @arizeai/phoenix-otel
Quick Start
The simplest way to get started is to use the register function with minimal configuration:
import { register } from "@arizeai/phoenix-otel";
// Register with default settings (connects to localhost:6006)
register({
projectName: "my-app",
});
For production use with Arize Phoenix cloud:
import { register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app",
url: "https://app.phoenix.arize.com/s/your-space-name",
apiKey: "your-api-key",
});
Configuration
Environment Variables
The package automatically reads from the following environment variables if configuration parameters are not provided:
PHOENIX_COLLECTOR_ENDPOINT - The URL to the Phoenix collector endpoint
PHOENIX_API_KEY - The API key for authentication
Example:
PHOENIX_COLLECTOR_ENDPOINT='https://app.phoenix.arize.com/s/your-space-name' \
PHOENIX_API_KEY='your-api-key' \
node your-app.js
Configuration Options
The register function accepts a RegisterParams object with the following options:
| Parameter | Type | Default | Description |
|---|
projectName | string | "default" | The project name that spans should be associated with |
url | string | "http://localhost:6006" | The URL to the Phoenix server (can include tracing path) |
apiKey | string | undefined | The API key for Phoenix instance authentication |
headers | Record<string, string> | {} | Custom headers to include in OTLP requests |
batch | boolean | true | Whether to use batch span processing (recommended for production) |
instrumentations | Instrumentation[] | undefined | Array of OpenTelemetry instrumentations to register |
global | boolean | true | Whether to set the tracer as a global provider |
diagLogLevel | DiagLogLevel | undefined | Diagnostic logging level for debugging |
Usage Examples
Basic Configuration
import { register } from "@arizeai/phoenix-otel";
const provider = register({
projectName: "my-application",
url: "http://localhost:6006",
batch: true,
});
With Auto-Instrumentation
Automatically instrument common libraries (works best with CommonJS projects):
import { register } from "@arizeai/phoenix-otel";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
register({
projectName: "my-express-app",
url: "https://app.phoenix.arize.com/s/your-space-name",
apiKey: process.env.PHOENIX_API_KEY,
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation(),
],
});
Note: Auto-instrumentation may only work with CommonJS projects. ESM projects will require manually applying instrumentation.
import { register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app",
url: "https://app.phoenix.arize.com/s/your-space-name",
headers: {
"X-Custom-Header": "custom-value",
},
});
Development vs Production Configuration
For development with local Phoenix instance:
import { register } from "@arizeai/phoenix-otel";
import { DiagLogLevel } from "@opentelemetry/api";
register({
projectName: "my-app-dev",
url: "http://localhost:6006",
batch: false, // Use simple span processor for immediate feedback
diagLogLevel: DiagLogLevel.DEBUG, // Enable debug logging
});
For production:
import { register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app-prod",
url: "https://app.phoenix.arize.com/s/your-space-name",
apiKey: process.env.PHOENIX_API_KEY,
batch: true, // Use batch processing for better performance
});
Spans may not be exported if still queued in the processor when your process exits. With batch: true, call await provider.shutdown() to explicitly flush before exit. Alternatively, use batch: false for immediate export.
Manual Tracing
After registration, you can create custom spans using the OpenTelemetry API:
import { register, trace } from "@arizeai/phoenix-otel";
register({ projectName: "my-app" });
const tracer = trace.getTracer("my-tracer");
async function myFunction() {
return tracer.startActiveSpan("my-operation", async (span) => {
try {
// Your code here
const result = await someOperation();
span.setAttribute("result.count", result.length);
return result;
} catch (error) {
span.recordException(error as Error);
throw error;
} finally {
span.end();
}
});
}
Non-Global Provider
If you don’t want to set the provider globally:
import { register } from "@arizeai/phoenix-otel";
const provider = register({
projectName: "my-app",
global: false, // Don't register globally
});
// Use the provider explicitly
const tracer = provider.getTracer("my-tracer");