Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Langfuse Langfuse ObservationTypeMapper

From Leeroopedia
Knowledge Sources
Domains Observability, OpenTelemetry, AI Frameworks
Last Updated 2026-02-14 00:00 GMT

Overview

Concrete tool for classifying OpenTelemetry spans into Langfuse observation types via a priority-ordered mapper registry provided by Langfuse.

Description

The ObservationTypeMapperRegistry class maintains an ordered list of ObservationTypeMapper instances, each with a priority number. When mapToObservationType() is called, the registry iterates through mappers sorted by priority (ascending), calling canMap() then mapToObservationType() on each. The first mapper that returns a non-null result wins. If none match, the default is SPAN.

Two mapper base classes are provided:

  • SimpleAttributeMapper: Checks for a single attribute key and maps its value through a static dictionary. Used for straightforward 1:1 mappings (P1: Langfuse direct, P2: OpenInference, P3: GenAI operation).
  • CustomAttributeMapper: Accepts arbitrary canMapFn and mapFn closures for complex multi-attribute logic. Used for conditional detection (P0: Python SDK override, P4/P5: Vercel AI SDK, P6: GenAI tool, P7: model-based fallback).

The sorted mapper list is cached after first computation for performance.

Usage

The registry is instantiated once as a module-level singleton in OtelIngestionProcessor.ts and used during both processToIngestionEvents() and processToEvent() to classify each span.

Code Reference

Source Location

  • Repository: langfuse
  • File: packages/shared/src/server/otel/ObservationTypeMapper.ts
  • Lines: 152-432 (registry class), 412-432 (main mapToObservationType method)

Signature

class ObservationTypeMapperRegistry {
  mapToObservationType(
    attributes: Record<string, unknown>,
    resourceAttributes?: Record<string, unknown>,
    scopeData?: Record<string, unknown>,
  ): LangfuseObservationType;

  getMappersForDebugging(): ReadonlyArray<ObservationTypeMapper>;
}

Import

import { ObservationTypeMapperRegistry } from "@langfuse/shared/src/server/otel/ObservationTypeMapper";

I/O Contract

Inputs

Name Type Required Description
attributes Record<string, unknown> Yes Span-level attributes extracted from the OTel span (e.g., langfuse.observation.type, gen_ai.operation.name, openinference.span.kind)
resourceAttributes Record<string, unknown> No Resource-level attributes from the OTel resourceSpan (e.g., telemetry.sdk.language)
scopeData Record<string, unknown> No Instrumentation scope metadata (e.g., { name: "langfuse-sdk", version: "3.5.0" })

Outputs

Name Type Description
LangfuseObservationType string (enum key) One of: SPAN, GENERATION, EVENT, EMBEDDING, AGENT, TOOL, CHAIN, RETRIEVER, GUARDRAIL, EVALUATOR. Defaults to SPAN if no mapper matches.

Usage Examples

Basic Type Detection

const registry = new ObservationTypeMapperRegistry();

// Langfuse SDK span with explicit type
const type1 = registry.mapToObservationType(
  { "langfuse.observation.type": "generation" },
);
// Returns: "GENERATION"

// OpenInference LLM span
const type2 = registry.mapToObservationType(
  { "openinference.span.kind": "LLM" },
);
// Returns: "GENERATION"

// Vercel AI SDK generation with model
const type3 = registry.mapToObservationType(
  {
    "operation.name": "ai.generateText.doGenerate",
    "ai.model.id": "gpt-4o",
  },
);
// Returns: "GENERATION"

// Unknown span with model attribute (P7 fallback)
const type4 = registry.mapToObservationType(
  { "gen_ai.request.model": "claude-3-opus" },
);
// Returns: "GENERATION"

// Plain span with no recognized attributes
const type5 = registry.mapToObservationType({});
// Returns: "SPAN"

Python SDK v3.3.0 Override (P0)

const registry = new ObservationTypeMapperRegistry();

// Python SDK <= 3.3.0 incorrectly sets type to "span" for generations
const type = registry.mapToObservationType(
  {
    "langfuse.observation.type": "span",
    "langfuse.observation.model.name": "gpt-4",
    "langfuse.observation.usage_details": '{"input": 100, "output": 50}',
  },
  { "telemetry.sdk.language": "python" },
  { name: "langfuse-sdk", version: "3.2.0" },
);
// Returns: "GENERATION" (P0 override corrects the misclassification)

GenAI Tool Call Detection (P6)

const registry = new ObservationTypeMapperRegistry();

// Pydantic AI tool call (no gen_ai.operation.name set)
const type = registry.mapToObservationType(
  {
    "gen_ai.tool.name": "search_database",
    "gen_ai.tool.call.id": "call_abc123",
  },
);
// Returns: "TOOL"

Related Pages

Implements Principle

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment