Skip to content

Commit 1c18a7f

Browse files
author
Andrei Bratu
committed
Added instrumentation function
1 parent 25faed6 commit 1c18a7f

File tree

5 files changed

+101
-11
lines changed

5 files changed

+101
-11
lines changed

.fernignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
11
# Specify files that shouldn't be modified by Fern
2+
3+
# Custom code
4+
5+
src/otel
6+
src/eval_utils
7+
src/decorators
8+
src/index.ts
9+
src/humanloop.client/ts
10+
11+
# Tests
12+
13+
tests
14+
15+
# CI Action
16+
17+
.github/workflows/ci.yml

src/humanloop.client.ts

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,53 @@
1-
import { HumanloopClient as FernClient } from "./Client";
1+
import { NodeTracerProvider, Tracer } from "@opentelemetry/sdk-trace-node";
2+
import { HumanloopClient as BaseHumanloopClient } from "./Client";
3+
import { HumanloopSpanProcessor } from "otel/processor";
4+
import { HumanloopSpanExporter } from "otel/exporter";
5+
import { instrumentProvider } from "otel";
6+
import { UtilityPromptKernel, prompt as promptUtilityFactory } from "decorators/prompt";
7+
import { tool as toolUtilityFactory } from "decorators/tool";
8+
import { flow as flowUtilityFactory } from "decorators/flow";
9+
import { ToolKernelRequest } from "api/types/ToolKernelRequest";
10+
import { FlowKernelRequest } from "api/types/FlowKernelRequest";
211

3-
export class HumanloopClient extends FernClient {
4-
5-
}
12+
export class HumanloopClient extends BaseHumanloopClient {
13+
protected readonly opentelemetryTracerProvider: NodeTracerProvider;
14+
protected readonly opentelemetryTracer: Tracer;
15+
16+
constructor(
17+
_options: BaseHumanloopClient.Options,
18+
opentelemetryTracerProvider: NodeTracerProvider,
19+
opentelemetryTracer: Tracer
20+
) {
21+
super(_options);
22+
23+
if (opentelemetryTracerProvider) {
24+
this.opentelemetryTracerProvider = opentelemetryTracerProvider;
25+
} else {
26+
this.opentelemetryTracerProvider = new NodeTracerProvider({
27+
spanProcessors: [new HumanloopSpanProcessor(new HumanloopSpanExporter(this))],
28+
});
29+
}
30+
31+
instrumentProvider(this.opentelemetryTracerProvider);
32+
33+
this.opentelemetryTracerProvider.register();
34+
35+
if (this.opentelemetryTracerProvider !== undefined) {
36+
this.opentelemetryTracer = this.opentelemetryTracerProvider.getTracer("humanloop.sdk");
37+
} else {
38+
this.opentelemetryTracer = opentelemetryTracer;
39+
}
40+
}
41+
42+
public prompt<T extends (...args: any[]) => any>(func: T, promptKernel?: UtilityPromptKernel, path?: string) {
43+
return promptUtilityFactory(this.opentelemetryTracer, func, promptKernel, path);
44+
}
45+
46+
public tool<T extends (...args: any[]) => any>(func: T, toolKernel: ToolKernelRequest, path?: string) {
47+
return toolUtilityFactory(this.opentelemetryTracer, func, toolKernel, path);
48+
}
49+
50+
public flow<T extends (...args: any[]) => any>(func: T, flowKernel: FlowKernelRequest, path?: string) {
51+
return flowUtilityFactory(this.opentelemetryTracer, func, flowKernel, path);
52+
}
53+
}

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export * as Humanloop from "./api";
2-
export { HumanloopClient } from "./Client";
2+
export { HumanloopClient } from "./humanloop.client";
33
export { HumanloopEnvironment } from "./environments";
44
export { HumanloopError, HumanloopTimeoutError } from "./errors";

src/otel/flow.context.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/otel/helpers.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import { ReadableSpan } from "@opentelemetry/sdk-trace-base";
22
import { SpanKind } from "@opentelemetry/api";
33
import { AttributeValue } from "@opentelemetry/api";
4+
import { InstrumentationBase } from "@opentelemetry/instrumentation";
45
import { v4 as uuidv4 } from "uuid";
56

67
// Constants for Humanloop attributes
7-
import { HUMANLOOP_FILE_KEY, HUMANLOOP_FILE_TYPE_KEY, HUMANLOOP_LOG_KEY } from "./constants";
8+
import { HUMANLOOP_FILE_TYPE_KEY } from "./constants";
9+
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
10+
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
11+
import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
12+
import { CohereInstrumentation } from "@traceloop/instrumentation-cohere";
813

914
export type NestedDict = { [key: string]: NestedDict | AttributeValue };
1015
export type NestedList = Array<NestedDict | AttributeValue>;
@@ -226,3 +231,29 @@ export function jsonifyIfNotString(func: Function, output: any): string {
226231
}
227232
return output;
228233
}
234+
235+
export function instrumentProvider(provider: NodeTracerProvider) {
236+
const instrumentors = [];
237+
try {
238+
const openai = require("openai").openai;
239+
const openaiInstrumentor = new OpenAIInstrumentation({ enrichTokens: true });
240+
openaiInstrumentor.manuallyInstrument(openai);
241+
instrumentors.push(openaiInstrumentor);
242+
} catch (error) {}
243+
try {
244+
const anthropic = require("@anthropic-ai/sdk");
245+
const anthropicInstrumentor = new AnthropicInstrumentation();
246+
anthropicInstrumentor.manuallyInstrument(anthropic);
247+
instrumentors.push(anthropicInstrumentor);
248+
} catch (error) {}
249+
try {
250+
const cohere = require("cohere");
251+
const cohereInstrumentor = new CohereInstrumentation();
252+
cohereInstrumentor.manuallyInstrument(cohere);
253+
instrumentors.push(cohereInstrumentor);
254+
} catch (error) {}
255+
for (const instrumentor of instrumentors) {
256+
instrumentor.setTracerProvider(provider);
257+
instrumentor.enable();
258+
}
259+
}

0 commit comments

Comments
 (0)