Telemetry
Adds OpenTelemetry GenAI attributes to Effect AI spans.
This module models the gen_ai.* attributes used by language model and
embedding providers. It includes attribute types, helpers for writing
non-null attributes onto existing spans, and a CurrentSpanTransformer
service for adding custom span annotations from provider options and response
parts.
Annotations
addGenAIAnnotations
Applies GenAI telemetry attributes to an OpenTelemetry span.
When to use
Use when you need to write GenAI request, response, token, or usage attributes onto an existing OpenTelemetry span.
Details
This function adds standardized GenAI attributes to a span following OpenTelemetry semantic conventions.
Gotchas
This function mutates the provided span in-place.
Signature
declare const addGenAIAnnotations: { (options: GenAITelemetryAttributeOptions): (span: Span) => void; (span: Span, options: GenAITelemetryAttributeOptions): void;}Example
(Adding GenAI telemetry annotations)
import { Effect } from "effect"import { Telemetry } from "effect/unstable/ai"
const directUsage = Effect.gen(function*() { const span = yield* Effect.currentSpan
Telemetry.addGenAIAnnotations(span, { system: "openai", request: { model: "gpt-4", temperature: 0.7 }, usage: { inputTokens: 100, outputTokens: 50 } }) return (span as { attributes: ReadonlyMap<string, unknown> }).attributes.size})
await Effect.runPromise(Effect.withSpan(directUsage, "example")) // => 5addSpanAttributes
Creates a reusable span-attribute writer for a key prefix and key transformer.
Details
The returned function mutates the supplied span by adding each non-nullish
attribute as ${prefix}.${transformedKey}.
Signature
declare function addSpanAttributes(keyPrefix: string, transformKey: (key: string) => string): <Attributes extends Record<string, any>>(span: Span, attributes: Attributes) => voidExample
(Adding prefixed span attributes)
import { Context, Option, String, Tracer } from "effect"import { Telemetry } from "effect/unstable/ai"
const addCustomAttributes = Telemetry.addSpanAttributes( "custom.ai", String.camelToSnake)
const span = new Tracer.NativeSpan({ name: "request", parent: Option.none(), annotations: Context.empty(), links: [], startTime: 0n, kind: "internal", sampled: true})
addCustomAttributes(span, { modelName: "gpt-4", maxTokens: 1000})
Array.from(span.attributes.keys()) // => ["custom.ai.model_name", "custom.ai.max_tokens"]Models
AllAttributes type
All telemetry attributes which are part of the GenAI specification.
Signature
type AllAttributes = BaseAttributes & OperationAttributes & TokenAttributes & UsageAttributes & RequestAttributes & ResponseAttributesBaseAttributes interface
Telemetry attributes which are part of the GenAI specification and are
namespaced by gen_ai.
Signature
interface BaseAttributes { readonly system?: string & {} | WellKnownSystem | null;}GenAITelemetryAttributes type
The attributes used to describe telemetry in the context of Generative Artificial Intelligence (GenAI) models requests and responses.
Details
These attributes follow the OpenTelemetry generative AI semantic conventions: https://opentelemetry.io/docs/specs/semconv/attributes-registry/gen-ai/
Signature
type GenAITelemetryAttributes = Struct.Simplify<AttributesWithPrefix<BaseAttributes, "gen_ai"> & AttributesWithPrefix<OperationAttributes, "gen_ai.operation"> & AttributesWithPrefix<TokenAttributes, "gen_ai.token"> & AttributesWithPrefix<UsageAttributes, "gen_ai.usage"> & AttributesWithPrefix<RequestAttributes, "gen_ai.request"> & AttributesWithPrefix<ResponseAttributes, "gen_ai.response">>OperationAttributes interface
Telemetry attributes which are part of the GenAI specification and are
namespaced by gen_ai.operation.
Signature
interface OperationAttributes { readonly name?: string & {} | WellKnownOperationName | null;}RequestAttributes interface
Telemetry attributes which are part of the GenAI specification and are
namespaced by gen_ai.request.
Signature
interface RequestAttributes { readonly encodingFormats?: readonly Array<string> | null; readonly frequencyPenalty?: number | null; readonly maxTokens?: number | null; readonly model?: string | null; readonly presencePenalty?: number | null; readonly seed?: number | null; readonly stopSequences?: readonly Array<string> | null; readonly temperature?: number | null; readonly topK?: number | null; readonly topP?: number | null;}ResponseAttributes interface
Telemetry attributes which are part of the GenAI specification and are
namespaced by gen_ai.response.
Signature
interface ResponseAttributes { readonly finishReasons?: readonly Array<string> | null; readonly id?: string | null; readonly model?: string | null;}SpanTransformer interface
A function that can transform OpenTelemetry spans based on AI operation data.
Details
Span transformers receive the complete request/response context from AI operations and can add custom telemetry attributes, metrics, or other observability data.
Signature
interface SpanTransformer { (options: ProviderOptions & { readonly response: readonly Array<AllParts<any>>; }): void;}Example
(Transforming AI spans)
import type { Telemetry } from "effect/unstable/ai"
const customTransformer: Telemetry.SpanTransformer = ({ response, span }) => { // Add custom attributes based on the response const textParts = response.filter((part) => part.type === "text") const totalTextLength = textParts.reduce( (sum, part) => sum + (part.type === "text" ? part.text.length : 0), 0 ) span.attribute("total_text_length", totalTextLength)}
typeof customTransformer // => "function"TokenAttributes interface
Telemetry attributes which are part of the GenAI specification and are
namespaced by gen_ai.token.
Signature
interface TokenAttributes { readonly type?: string | null;}UsageAttributes interface
Telemetry attributes which are part of the GenAI specification and are
namespaced by gen_ai.usage.
Signature
interface UsageAttributes { readonly inputTokens?: number | null; readonly outputTokens?: number | null;}WellKnownOperationName type
The gen_ai.operation.name attribute has the following list of well-known
values.
Details
If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used.
Signature
type WellKnownOperationName = "chat" | "embeddings" | "text_completion"WellKnownSystem type
The gen_ai.system attribute has the following list of well-known values.
Details
If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used.
Signature
type WellKnownSystem = "anthropic" | "aws.bedrock" | "az.ai.inference" | "az.ai.openai" | "cohere" | "deepseek" | "gemini" | "groq" | "ibm.watsonx.ai" | "mistral_ai" | "openai" | "perplexity" | "vertex_ai" | "xai"Options
GenAITelemetryAttributeOptions type
Configuration options for GenAI telemetry attributes.
Details
Combines base attributes with optional grouped attributes for comprehensive telemetry coverage of AI operations.
Signature
type GenAITelemetryAttributeOptions = BaseAttributes & { readonly operation?: OperationAttributes; readonly request?: RequestAttributes; readonly response?: ResponseAttributes; readonly token?: TokenAttributes; readonly usage?: UsageAttributes;}Example
(Configuring GenAI telemetry attributes)
import type { Telemetry } from "effect/unstable/ai"
const telemetryOptions: Telemetry.GenAITelemetryAttributeOptions = { system: "openai", operation: { name: "chat" }, request: { model: "gpt-4-turbo", temperature: 0.7, maxTokens: 2000 }, response: { id: "chatcmpl-123", model: "gpt-4-turbo-2024-04-09", finishReasons: ["stop"] }, usage: { inputTokens: 50, outputTokens: 25 }}
const result = [telemetryOptions.system, telemetryOptions.usage?.inputTokens] // => ["openai", 50]Services
CurrentSpanTransformer
Service tag for providing a SpanTransformer to large language model
operations.
When to use
Use to retrieve or provide the current SpanTransformer through context for
language model span annotation.
See
- SpanTransformer for the transformer contract provided by this service
Signature
declare class CurrentSpanTransformer extends Shape<"effect/ai/Telemetry/CurrentSpanTransformer", SpanTransformer, this> { constructor(_: never);}Utility Types
AttributesWithPrefix type
Utility type for prefixing attribute names with a namespace.
Details
Transforms attribute keys by adding a prefix and formatting them according to OpenTelemetry conventions (camelCase to snake_case).
Signature
type AttributesWithPrefix<Attributes extends Record<string, any>, Prefix extends string> = { [Name in keyof Attributes]: Attributes[Name] }Example
(Prefixing telemetry attributes)
import type { Telemetry } from "effect/unstable/ai"
type RequestAttrs = { modelName: string maxTokens: number}
type PrefixedAttrs = Telemetry.AttributesWithPrefix< RequestAttrs, "gen_ai.request">// Results in: {// "gen_ai.request.model_name": string// "gen_ai.request.max_tokens": number// }const attributes: PrefixedAttrs = { "gen_ai.request.model_name": "gpt-4", "gen_ai.request.max_tokens": 1000}Object.keys(attributes) // => ["gen_ai.request.model_name", "gen_ai.request.max_tokens"]FormatAttributeName type
Utility type for converting camelCase names to snake_case format.
Details
This type recursively transforms string literal types from camelCase to snake_case, which is the standard format for OpenTelemetry attributes.
Signature
type FormatAttributeName<T extends string | number | symbol> = T extends string ? T extends `${infer First}${infer Rest}` ? `${First extends Uppercase<First> ? "_" : ""}${Lowercase<First>}${FormatAttributeName<Rest>}` : T : neverExample
(Formatting attribute names)
import type { Telemetry } from "effect/unstable/ai"
type Formatted1 = Telemetry.FormatAttributeName<"modelName"> // "model_name"type Formatted2 = Telemetry.FormatAttributeName<"maxTokens"> // "max_tokens"type Formatted3 = Telemetry.FormatAttributeName<"temperature"> // "temperature"
const formatted: [Formatted1, Formatted2, Formatted3] = [ "model_name", "max_tokens", "temperature"]formatted // => ["model_name", "max_tokens", "temperature"]