Skip to content

fix(traceloop-sdk): omit spans of non-traceloop instrumentations by default when using standalone processor #598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/sample-app/src/sample_otel_sdk.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NodeSDK } from "@opentelemetry/sdk-node";
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import {
createSpanProcessor,
withTask,
Expand All @@ -13,12 +13,13 @@ const traceloopSpanProcessor = createSpanProcessor({
apiKey: process.env.TRACELOOP_API_KEY,
baseUrl: process.env.TRACELOOP_BASE_URL,
disableBatch: true,
allowedInstrumentationLibraries: ["my-sample-app"],
});

// Initialize the OpenTelemetry SDK with Traceloop's span processor
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "my-sample-app",
[ATTR_SERVICE_NAME]: "my-sample-app",
}),
spanProcessors: [traceloopSpanProcessor],
});
Expand Down
11 changes: 7 additions & 4 deletions packages/traceloop-sdk/src/lib/tracing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { baggageUtils } from "@opentelemetry/core";
import { context, diag } from "@opentelemetry/api";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { Resource } from "@opentelemetry/resources";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { Instrumentation } from "@opentelemetry/instrumentation";
import { InitializeOptions } from "../interfaces";
import { Telemetry } from "../telemetry/telemetry";
Expand All @@ -25,7 +25,10 @@ import { LangChainInstrumentation } from "@traceloop/instrumentation-langchain";
import { ChromaDBInstrumentation } from "@traceloop/instrumentation-chromadb";
import { QdrantInstrumentation } from "@traceloop/instrumentation-qdrant";
import { TogetherInstrumentation } from "@traceloop/instrumentation-together";
import { createSpanProcessor } from "./span-processor";
import {
ALL_INSTRUMENTATION_LIBRARIES,
createSpanProcessor,
} from "./span-processor";

let _sdk: NodeSDK;
let _spanProcessor: SpanProcessor;
Expand Down Expand Up @@ -268,6 +271,7 @@ export const startTracing = (options: InitializeOptions) => {
disableBatch: options.disableBatch,
exporter: traceExporter,
headers,
allowedInstrumentationLibraries: ALL_INSTRUMENTATION_LIBRARIES,
});

const spanProcessors: SpanProcessor[] = [_spanProcessor];
Expand All @@ -277,8 +281,7 @@ export const startTracing = (options: InitializeOptions) => {

_sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]:
options.appName || process.env.npm_package_name,
[ATTR_SERVICE_NAME]: options.appName || process.env.npm_package_name,
}),
spanProcessors,
contextManager: options.contextManager,
Expand Down
54 changes: 52 additions & 2 deletions packages/traceloop-sdk/src/lib/tracing/span-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {
} from "./tracing";
import { SpanAttributes } from "@traceloop/ai-semantic-conventions";

export const ALL_INSTRUMENTATION_LIBRARIES = "all" as const;
type AllInstrumentationLibraries = typeof ALL_INSTRUMENTATION_LIBRARIES;

export interface SpanProcessorOptions {
/**
* The API Key for sending traces data. Optional.
Expand Down Expand Up @@ -44,6 +47,14 @@ export interface SpanProcessorOptions {
* The headers to be sent with the traces data. Optional.
*/
headers?: Record<string, string>;

/**
* The instrumentation libraries to be allowed in the traces. Optional.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd have a slightly different behavior here - if the parameter is undefined - then it's all instrumentation libraries. If it's set - then whatever is set (which can either be an array of library names or TRACELOOP_INSTRUMENTATION_LIBRARIES) - wdyt?

Copy link
Contributor Author

@galkleinman galkleinman Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought of this option, it'll force users of the standalone processor to assign TRACELOOP_INSTRUMENTATION_LIBRARIES for instrumentationLis argument instead of having it working by default

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it makes more sense tho imo, but has some more friction

* Defaults to Traceloop instrumentation libraries.
* If set to ALL_INSTRUMENTATION_LIBRARIES, all instrumentation libraries will be allowed.
* If set to an array of instrumentation libraries, only traceloop instrumentation libraries and the specified instrumentation libraries will be allowed.
*/
allowedInstrumentationLibraries?: string[] | AllInstrumentationLibraries;
}

/**
Expand Down Expand Up @@ -78,11 +89,40 @@ export const createSpanProcessor = (
const originalOnEnd = spanProcessor.onEnd.bind(spanProcessor);

spanProcessor.onStart = onSpanStart;
spanProcessor.onEnd = onSpanEnd(originalOnEnd);

if (
options.allowedInstrumentationLibraries === ALL_INSTRUMENTATION_LIBRARIES
) {
spanProcessor.onEnd = onSpanEnd(originalOnEnd);
} else {
const instrumentationLibraries = traceloopInstrumentationLibraries;

if (options.allowedInstrumentationLibraries) {
instrumentationLibraries.push(...options.allowedInstrumentationLibraries);
}

spanProcessor.onEnd = onSpanEnd(originalOnEnd, instrumentationLibraries);
}

return spanProcessor;
};

export const traceloopInstrumentationLibraries = [
"@traceloop/node-server-sdk",
"@traceloop/instrumentation-openai",
"@traceloop/instrumentation-langchain",
"@traceloop/instrumentation-chroma",
"@traceloop/instrumentation-anthropic",
"@traceloop/instrumentation-azure",
"@traceloop/instrumentation-llamaindex",
"@traceloop/instrumentation-vertexai",
"@traceloop/instrumentation-bedrock",
"@traceloop/instrumentation-cohere",
"@traceloop/instrumentation-pinecone",
"@traceloop/instrumentation-qdrant",
"@traceloop/instrumentation-together",
];

/**
* Handles span start event, enriching it with workflow and entity information
*/
Expand Down Expand Up @@ -119,8 +159,18 @@ const onSpanStart = (span: Span): void => {
/**
* Handles span end event, adapting attributes for Vercel AI compatibility
*/
const onSpanEnd = (originalOnEnd: (span: ReadableSpan) => void) => {
const onSpanEnd = (
originalOnEnd: (span: ReadableSpan) => void,
instrumentationLibraries?: string[],
) => {
return (span: ReadableSpan): void => {
if (
instrumentationLibraries &&
!instrumentationLibraries.includes(span.instrumentationLibrary.name)
) {
return;
}

// Vercel AI Adapters
const attributes = span.attributes;

Expand Down
2 changes: 1 addition & 1 deletion packages/traceloop-sdk/src/lib/tracing/tracing.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { trace, createContextKey } from "@opentelemetry/api";
import { Context } from "@opentelemetry/api/build/src/context/types";

const TRACER_NAME = "traceloop.tracer";
const TRACER_NAME = "@traceloop/node-server-sdk";
export const WORKFLOW_NAME_KEY = createContextKey("workflow_name");
export const ENTITY_NAME_KEY = createContextKey("entity_name");
export const ASSOCATION_PROPERTIES_KEY = createContextKey(
Expand Down