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/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/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, 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.7.0"
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



78
79
80
# File 'lib/langfuse.rb', line 78

def configuration
  @configuration ||= Config.new
end

Class Method Details

.clientClient

Returns the global singleton client

Returns:

  • (Client)

    the global client instance



104
105
106
# File 'lib/langfuse.rb', line 104

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



92
93
94
95
96
97
98
99
# File 'lib/langfuse.rb', line 92

def configure
  yield(configuration)

  # Auto-initialize OpenTelemetry
  OtelSetup.setup(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



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/langfuse.rb', line 217

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



314
315
316
# File 'lib/langfuse.rb', line 314

def create_trace_id(seed: nil)
  TraceId.create(seed: seed)
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


296
297
298
# File 'lib/langfuse.rb', line 296

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



128
129
130
# File 'lib/langfuse.rb', line 128

def force_flush(timeout: 30)
  OtelSetup.force_flush(timeout: timeout)
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



407
408
409
410
411
412
413
# File 'lib/langfuse.rb', line 407

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



178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/langfuse.rb', line 178

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)



321
322
323
324
325
326
327
328
329
330
# File 'lib/langfuse.rb', line 321

def reset!
  client.shutdown if @client
  OtelSetup.shutdown(timeout: 5) if OtelSetup.initialized?
  @configuration = nil
  @client = nil
rescue StandardError
  # Ignore shutdown errors during reset (e.g., in tests)
  @configuration = nil
  @client = nil
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



252
253
254
255
256
257
258
259
260
# File 'lib/langfuse.rb', line 252

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



278
279
280
281
282
283
284
285
286
# File 'lib/langfuse.rb', line 278

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



119
120
121
122
# File 'lib/langfuse.rb', line 119

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



362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/langfuse.rb', line 362

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