Module: Langfuse

Defined in:
lib/langfuse.rb,
lib/langfuse.rb,
lib/langfuse/types.rb,
lib/langfuse/client.rb,
lib/langfuse/config.rb,
lib/langfuse/masking.rb,
lib/langfuse/version.rb,
lib/langfuse/sampling.rb,
lib/langfuse/trace_id.rb,
lib/langfuse/api_client.rb,
lib/langfuse/evaluation.rb,
lib/langfuse/otel_setup.rb,
lib/langfuse/item_result.rb,
lib/langfuse/propagation.rb,
lib/langfuse/span_filter.rb,
lib/langfuse/cache_warmer.rb,
lib/langfuse/observations.rb,
lib/langfuse/prompt_cache.rb,
lib/langfuse/score_client.rb,
lib/langfuse/dataset_client.rb,
lib/langfuse/span_processor.rb,
lib/langfuse/experiment_item.rb,
lib/langfuse/otel_attributes.rb,
lib/langfuse/timestamp_parser.rb,
lib/langfuse/traced_execution.rb,
lib/langfuse/experiment_result.rb,
lib/langfuse/experiment_runner.rb,
lib/langfuse/chat_prompt_client.rb,
lib/langfuse/text_prompt_client.rb,
lib/langfuse/dataset_item_client.rb,
lib/langfuse/rails_cache_adapter.rb,
lib/langfuse/stale_while_revalidate.rb

Overview

rubocop:disable Metrics/ModuleLength

Defined Under Namespace

Modules: Masking, ModelSetters, OtelAttributes, OtelSetup, Propagation, Sampling, StaleWhileRevalidate, TimestampParser, TraceId, TracedExecution, Types Classes: Agent, ApiClient, ApiError, BaseObservation, CacheWarmer, CacheWarmingError, Chain, ChatPromptClient, Client, Config, ConfigurationError, DatasetClient, DatasetItemClient, Embedding, Error, Evaluation, Evaluator, Event, ExperimentItem, ExperimentResult, ExperimentRunner, Generation, Guardrail, ItemResult, NotFoundError, PromptCache, RailsCacheAdapter, Retriever, ScoreClient, Span, SpanProcessor, TextPromptClient, Tool, UnauthorizedError

Constant Summary collapse

FLUSH_TIMEOUT =

Default timeout (in seconds) for flushing traces during experiment runs.

5
OBSERVATION_TYPE_REGISTRY =

Registry mapping observation type strings to their wrapper classes

{
  OBSERVATION_TYPES[:generation] => Generation,
  OBSERVATION_TYPES[:embedding] => Embedding,
  OBSERVATION_TYPES[:event] => Event,
  OBSERVATION_TYPES[:agent] => Agent,
  OBSERVATION_TYPES[:tool] => Tool,
  OBSERVATION_TYPES[:chain] => Chain,
  OBSERVATION_TYPES[:retriever] => Retriever,
  OBSERVATION_TYPES[:evaluator] => Evaluator,
  OBSERVATION_TYPES[:guardrail] => Guardrail,
  OBSERVATION_TYPES[:span] => Span
}.freeze
VERSION =
"0.8.0"
LANGFUSE_TRACER_NAME =

Instrumentation scope name used by module-level Langfuse tracing.

"langfuse-rb"
KNOWN_LLM_INSTRUMENTATION_SCOPE_PREFIXES =

Conservative allowlist of instrumentation scope prefixes that clearly belong to LLM workflows.

[
  LANGFUSE_TRACER_NAME,
  "agent_framework",
  "ai",
  "haystack",
  "langsmith",
  "litellm",
  "openinference",
  "opentelemetry.instrumentation.anthropic",
  "strands-agents",
  "vllm"
].freeze
OBSERVATION_TYPES =

Observation type constants

{
  span: "span",
  generation: "generation",
  embedding: "embedding",
  event: "event",
  agent: "agent",
  tool: "tool",
  chain: "chain",
  retriever: "retriever",
  evaluator: "evaluator",
  guardrail: "guardrail"
}.freeze

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.configurationConfig

Returns the global configuration object

Returns:

  • (Config)

    the global configuration



80
81
82
# File 'lib/langfuse.rb', line 80

def configuration
  @configuration ||= Config.new
end

Class Method Details

.clientClient

Returns the global singleton client

Returns:

  • (Client)

    the global client instance



102
103
104
# File 'lib/langfuse.rb', line 102

def client
  @client ||= Client.new(configuration)
end

.configure {|Config| ... } ⇒ Config

Configure Langfuse globally

Examples:

Langfuse.configure do |config|
  config.public_key = ENV['LANGFUSE_PUBLIC_KEY']
  config.secret_key = ENV['LANGFUSE_SECRET_KEY']
end

Yields:

  • (Config)

    the configuration object

Returns:

  • (Config)

    the configured configuration



94
95
96
97
# File 'lib/langfuse.rb', line 94

def configure
  yield(configuration)
  configuration
end

.create_score(name:, value:, id: nil, trace_id: nil, session_id: nil, observation_id: nil, comment: nil, metadata: nil, environment: nil, data_type: :numeric, dataset_run_id: nil, config_id: nil) ⇒ void

This method returns an undefined value.

Create a score event and queue it for batching

rubocop:disable Metrics/ParameterLists

Examples:

Numeric score

Langfuse.create_score(name: "quality", value: 0.85, trace_id: "abc123")

Boolean score

Langfuse.create_score(name: "passed", value: true, trace_id: "abc123", data_type: :boolean)

Categorical score

Langfuse.create_score(name: "category", value: "high", trace_id: "abc123", data_type: :categorical)

Parameters:

  • name (String)

    Score name (required)

  • value (Numeric, Integer, String)

    Score value (type depends on data_type)

  • id (String, nil) (defaults to: nil)

    Score ID

  • trace_id (String, nil) (defaults to: nil)

    Trace ID to associate with the score

  • session_id (String, nil) (defaults to: nil)

    Session ID to associate with the score

  • observation_id (String, nil) (defaults to: nil)

    Observation ID to associate with the score

  • comment (String, nil) (defaults to: nil)

    Optional comment

  • metadata (Hash, nil) (defaults to: nil)

    Optional metadata hash

  • environment (String, nil) (defaults to: nil)

    Optional environment

  • data_type (Symbol) (defaults to: :numeric)

    Data type (:numeric, :boolean, :categorical)

  • dataset_run_id (String, nil) (defaults to: nil)

    Optional dataset run ID to associate with the score

  • config_id (String, nil) (defaults to: nil)

    Optional score config ID

Raises:

  • (ArgumentError)

    if validation fails



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/langfuse.rb', line 237

def create_score(name:, value:, id: nil, trace_id: nil, session_id: nil, observation_id: nil, comment: nil,
                 metadata: nil, environment: nil, data_type: :numeric, dataset_run_id: nil, config_id: nil)
  client.create_score(
    name: name,
    value: value,
    id: id,
    trace_id: trace_id,
    session_id: session_id,
    observation_id: observation_id,
    comment: comment,
    metadata: ,
    environment: environment,
    data_type: data_type,
    dataset_run_id: dataset_run_id,
    config_id: config_id
  )
end

.create_trace_id(seed: nil) ⇒ String

Note:

Avoid PII or secrets as seeds. See Langfuse::TraceId.create for details.

Generate a trace ID (deterministic when seeded, random otherwise).

Use this to correlate Langfuse traces with external identifiers. The same seed always produces the same trace ID across the Ruby, Python, and JS SDKs (SHA-256 of the seed, first 16 bytes, as 32 hex chars).

Examples:

trace_id = Langfuse.create_trace_id(seed: "order-12345")
Langfuse.observe("process", trace_id: trace_id) { |span| ... }

Parameters:

  • seed (String, nil) (defaults to: nil)

    Optional deterministic seed

Returns:

  • (String)

    32-character lowercase hex trace ID

Raises:

  • (ArgumentError)

    if seed is not nil and not a String



334
335
336
# File 'lib/langfuse.rb', line 334

def create_trace_id(seed: nil)
  TraceId.create(seed: seed)
end

.default_export_span?(span) ⇒ Boolean Also known as: is_default_export_span

Return whether a span should be exported when no custom filter is configured.

Parameters:

  • span (#instrumentation_scope, #attributes)

    Span or span data to inspect

Returns:

  • (Boolean)


65
66
67
# File 'lib/langfuse/span_filter.rb', line 65

def default_export_span?(span)
  langfuse_span?(span) || genai_span?(span) || known_llm_instrumentor?(span)
end

.flush_scoresvoid

This method returns an undefined value.

Force flush all queued score events

Sends all queued score events to the API immediately.

Examples:

Langfuse.flush_scores


316
317
318
# File 'lib/langfuse.rb', line 316

def flush_scores
  client.flush_scores if @client
end

.force_flush(timeout: 30) ⇒ void

This method returns an undefined value.

Force flush all pending traces

Parameters:

  • timeout (Integer) (defaults to: 30)

    Timeout in seconds



148
149
150
# File 'lib/langfuse.rb', line 148

def force_flush(timeout: 30)
  OtelSetup.force_flush(timeout: timeout)
end

.genai_span?(span) ⇒ Boolean Also known as: is_genai_span

Return whether the span contains ‘gen_ai.*` attributes.

Parameters:

  • span (#attributes)

    Span or span data to inspect

Returns:

  • (Boolean)


39
40
41
42
43
44
# File 'lib/langfuse/span_filter.rb', line 39

def genai_span?(span)
  attributes = span.attributes
  return false unless attributes

  attributes.keys.any? { |key| key.is_a?(String) && key.start_with?("gen_ai.") }
end

.known_llm_instrumentor?(span) ⇒ Boolean Also known as: is_known_llm_instrumentor

Return whether the span came from a known LLM instrumentation scope.

Parameters:

  • span (#instrumentation_scope)

    Span or span data to inspect

Returns:

  • (Boolean)


50
51
52
53
54
55
56
57
58
59
# File 'lib/langfuse/span_filter.rb', line 50

def known_llm_instrumentor?(span)
  scope_name = instrumentation_scope_name(span)
  return false unless scope_name

  return true if KNOWN_LLM_INSTRUMENTATION_SCOPE_PREFIXES.include?(scope_name)

  KNOWN_LLM_INSTRUMENTATION_SCOPE_DOTTED_PREFIXES.any? do |dotted_prefix|
    scope_name.start_with?(dotted_prefix)
  end
end

.langfuse_span?(span) ⇒ Boolean Also known as: is_langfuse_span

Return whether the span was created by Langfuse’s tracer.

Parameters:

  • span (#instrumentation_scope)

    Span or span data to inspect

Returns:

  • (Boolean)


31
32
33
# File 'lib/langfuse/span_filter.rb', line 31

def langfuse_span?(span)
  instrumentation_scope_name(span) == LANGFUSE_TRACER_NAME
end

.observe(name, attrs = {}, as_type: :span, trace_id: nil, **kwargs) {|observation| ... } ⇒ BaseObservation, Object

User-facing convenience method for creating root observations

Examples:

Block-based API (auto-ends)

Langfuse.observe("operation") do |obs|
  result = perform_operation
  obs.update(output: result)
end

Stateful API (manual end)

obs = Langfuse.observe("operation", input: { data: "test" })
obs.update(output: { result: "success" })
obs.end

Parameters:

  • name (String)

    Descriptive name for the observation

  • attrs (Hash) (defaults to: {})

    Observation attributes (optional positional or keyword)

  • as_type (Symbol, String) (defaults to: :span)

    Observation type (:span, :generation, :event, etc.)

  • trace_id (String, nil) (defaults to: nil)

    Optional 32-char lowercase hex trace ID to attach the observation to. Use create_trace_id to generate one. Forwarded to start_observation.

  • kwargs (Hash)

    Additional keyword arguments merged into observation attributes (e.g., input:, output:, metadata:)

Yields:

  • (observation)

    Optional block that receives the observation object

Yield Parameters:

Returns:

  • (BaseObservation, Object)

    The observation (or block return value if block given)

Raises:

  • (ArgumentError)

    if an invalid ‘trace_id` is provided



431
432
433
434
435
436
437
# File 'lib/langfuse.rb', line 431

def observe(name, attrs = {}, as_type: :span, trace_id: nil, **kwargs, &block)
  merged_attrs = attrs.to_h.merge(kwargs)
  observation = start_observation(name, merged_attrs, as_type: as_type, trace_id: trace_id)
  return observation unless block

  observation.send(:run_in_context, &block)
end

.propagate_attributes(user_id: nil, session_id: nil, metadata: nil, version: nil, tags: nil, as_baggage: false) { ... } ⇒ Object

Propagate trace-level attributes to all spans created within this context.

This method sets attributes on the currently active span AND automatically propagates them to all new child spans created within the block. This is the recommended way to set trace-level attributes like user_id, session_id, and metadata dimensions that should be consistently applied across all observations in a trace.

IMPORTANT: Call this as early as possible within your trace/workflow. Only the currently active span and spans created after entering this context will have these attributes. Pre-existing spans will NOT be retroactively updated.

Examples:

Basic usage

Langfuse.propagate_attributes(user_id: "user_123", session_id: "session_abc") do
  Langfuse.observe("operation") do |span|
    # Current span has user_id and session_id
    span.start_observation("child") do |child|
      # Child span inherits user_id and session_id
    end
  end
end

With metadata and tags

Langfuse.propagate_attributes(
  user_id: "user_123",
  metadata: { environment: "production", region: "us-east" },
  tags: ["api", "v2"]
) do
  # All spans inherit these attributes
end

Cross-service propagation

Langfuse.propagate_attributes(
  user_id: "user_123",
  as_baggage: true
) do
  # Attributes propagate via HTTP headers
end

Parameters:

  • user_id (String, nil) (defaults to: nil)

    User identifier (≤200 characters)

  • session_id (String, nil) (defaults to: nil)

    Session identifier (≤200 characters)

  • metadata (Hash<String, String>, nil) (defaults to: nil)

    Additional metadata (all values ≤200 characters)

  • version (String, nil) (defaults to: nil)

    Version identifier (≤200 characters)

  • tags (Array<String>, nil) (defaults to: nil)

    List of tags (each ≤200 characters)

  • as_baggage (Boolean) (defaults to: false)

    If true, propagates via OpenTelemetry baggage for cross-service propagation

Yields:

  • Block within which attributes are propagated

Returns:

  • (Object)

    The result of the block



198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/langfuse.rb', line 198

def propagate_attributes(user_id: nil, session_id: nil, metadata: nil, version: nil, tags: nil,
                         as_baggage: false, &)
  Propagation.propagate_attributes(
    user_id: user_id,
    session_id: session_id,
    metadata: ,
    version: version,
    tags: tags,
    as_baggage: as_baggage,
    &
  )
end

.reset!void

This method returns an undefined value.

Reset global configuration and client (useful for testing)



341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/langfuse.rb', line 341

def reset!
  client.shutdown if @client
  OtelSetup.shutdown(timeout: 5) if OtelSetup.initialized?
  @configuration = nil
  @client = nil
  @noop_tracer = nil
  @tracing_disabled_warning_emitted = false
rescue StandardError
  # Ignore shutdown errors during reset (e.g., in tests)
  @configuration = nil
  @client = nil
  @noop_tracer = nil
  @tracing_disabled_warning_emitted = false
end

.score_active_observation(name:, value:, comment: nil, metadata: nil, data_type: :numeric) ⇒ void

This method returns an undefined value.

Create a score for the currently active observation (from OTel span)

Extracts observation_id and trace_id from the active OpenTelemetry span.

Examples:

Langfuse.observe("operation") do |obs|
  Langfuse.score_active_observation(name: "accuracy", value: 0.92)
end

Parameters:

  • name (String)

    Score name (required)

  • value (Numeric, Integer, String)

    Score value

  • comment (String, nil) (defaults to: nil)

    Optional comment

  • metadata (Hash, nil) (defaults to: nil)

    Optional metadata hash

  • data_type (Symbol) (defaults to: :numeric)

    Data type (:numeric, :boolean, :categorical)

Raises:

  • (ArgumentError)

    if no active span or validation fails



272
273
274
275
276
277
278
279
280
# File 'lib/langfuse.rb', line 272

def score_active_observation(name:, value:, comment: nil, metadata: nil, data_type: :numeric)
  client.score_active_observation(
    name: name,
    value: value,
    comment: comment,
    metadata: ,
    data_type: data_type
  )
end

.score_active_trace(name:, value:, comment: nil, metadata: nil, data_type: :numeric) ⇒ void

This method returns an undefined value.

Create a score for the currently active trace (from OTel span)

Extracts trace_id from the active OpenTelemetry span.

Examples:

Langfuse.observe("operation") do |obs|
  Langfuse.score_active_trace(name: "overall_quality", value: 5)
end

Parameters:

  • name (String)

    Score name (required)

  • value (Numeric, Integer, String)

    Score value

  • comment (String, nil) (defaults to: nil)

    Optional comment

  • metadata (Hash, nil) (defaults to: nil)

    Optional metadata hash

  • data_type (Symbol) (defaults to: :numeric)

    Data type (:numeric, :boolean, :categorical)

Raises:

  • (ArgumentError)

    if no active span or validation fails



298
299
300
301
302
303
304
305
306
# File 'lib/langfuse.rb', line 298

def score_active_trace(name:, value:, comment: nil, metadata: nil, data_type: :numeric)
  client.score_active_trace(
    name: name,
    value: value,
    comment: comment,
    metadata: ,
    data_type: data_type
  )
end

.shutdown(timeout: 30) ⇒ void

This method returns an undefined value.

Shutdown Langfuse and flush any pending traces and scores

Call this when shutting down your application to ensure all traces and scores are sent to Langfuse.

Examples:

In a Rails initializer or shutdown hook

at_exit { Langfuse.shutdown }

Parameters:

  • timeout (Integer) (defaults to: 30)

    Timeout in seconds



139
140
141
142
# File 'lib/langfuse.rb', line 139

def shutdown(timeout: 30)
  client.shutdown if @client
  OtelSetup.shutdown(timeout: timeout)
end

.start_observation(name, attrs = {}, as_type: :span, trace_id: nil, parent_span_context: nil, start_time: nil, skip_validation: false) ⇒ BaseObservation

Creates a new observation (root or child)

This is the module-level factory method that creates observations of any type. It can create root observations (when parent_span_context is nil) or child observations (when parent_span_context is provided).

rubocop:disable Metrics/ParameterLists

Examples:

Create root span

span = Langfuse.start_observation("root-operation", { input: {...} })

Create child generation

child = Langfuse.start_observation("llm-call", { model: "gpt-4" },
                                    as_type: :generation,
                                    parent_span_context: parent.otel_span.context)

Attach to a deterministic trace ID

trace_id = Langfuse.create_trace_id(seed: "order-123")
root = Langfuse.start_observation("process-order", trace_id: trace_id)

Parameters:

  • name (String)

    Descriptive name for the observation

  • attrs (Hash, Types::SpanAttributes, Types::GenerationAttributes, nil) (defaults to: {})

    Observation attributes

  • as_type (Symbol, String) (defaults to: :span)

    Observation type (:span, :generation, :event, etc.)

  • trace_id (String, nil) (defaults to: nil)

    Optional 32-char lowercase hex trace ID to attach the observation to. Mutually exclusive with ‘parent_span_context`. Use create_trace_id to generate one.

  • parent_span_context (OpenTelemetry::Trace::SpanContext, nil) (defaults to: nil)

    Parent span context for child observations

  • start_time (Time, Integer, nil) (defaults to: nil)

    Optional start time (Time object or Unix timestamp in nanoseconds)

  • skip_validation (Boolean) (defaults to: false)

    Skip validation (for internal use). Defaults to false.

Returns:

  • (BaseObservation)

    The observation wrapper (Span, Generation, or Event)

Raises:

  • (ArgumentError)

    if an invalid observation type is provided, an invalid ‘trace_id` is given, or both `trace_id` and `parent_span_context` are provided



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/langfuse.rb', line 386

def start_observation(name, attrs = {}, as_type: :span, trace_id: nil, parent_span_context: nil,
                      start_time: nil, skip_validation: false)
  parent_span_context = resolve_trace_context(trace_id, parent_span_context)
  type_str = as_type.to_s
  validate_observation_type!(as_type, type_str) unless skip_validation

  otel_tracer = otel_tracer()
  otel_span = create_otel_span(
    name: name,
    start_time: start_time,
    parent_span_context: parent_span_context,
    otel_tracer: otel_tracer
  )
  apply_observation_attributes(otel_span, type_str, attrs)

  observation = wrap_otel_span(otel_span, type_str, otel_tracer)
  # Events auto-end immediately when created
  observation.end if type_str == OBSERVATION_TYPES[:event]
  observation
end

.tracer_providerOpenTelemetry::SDK::Trace::TracerProvider

Return Langfuse’s internal tracer provider for explicit global OpenTelemetry installation.

Examples:

Langfuse.configure do |config|
  config.public_key = ENV["LANGFUSE_PUBLIC_KEY"]
  config.secret_key = ENV["LANGFUSE_SECRET_KEY"]
end

OpenTelemetry.tracer_provider = Langfuse.tracer_provider

Returns:

  • (OpenTelemetry::SDK::Trace::TracerProvider)

Raises:



118
119
120
121
122
123
124
125
126
# File 'lib/langfuse.rb', line 118

def tracer_provider
  unless tracing_config_ready?
    raise ConfigurationError,
          "Langfuse tracing is disabled until public_key, secret_key, and base_url are configured."
  end

  OtelSetup.setup(configuration) unless OtelSetup.initialized?
  OtelSetup.tracer_provider
end