Module: Langfuse

Defined in:
lib/langfuse.rb,
lib/langfuse.rb,
lib/langfuse/types.rb,
lib/langfuse/client.rb,
lib/langfuse/config.rb,
lib/langfuse/version.rb,
lib/langfuse/api_client.rb,
lib/langfuse/otel_setup.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/span_processor.rb,
lib/langfuse/otel_attributes.rb,
lib/langfuse/chat_prompt_client.rb,
lib/langfuse/text_prompt_client.rb,
lib/langfuse/rails_cache_adapter.rb,
lib/langfuse/stale_while_revalidate.rb

Overview

rubocop:disable Metrics/ModuleLength

Defined Under Namespace

Modules: OtelAttributes, OtelSetup, Propagation, StaleWhileRevalidate, Types Classes: Agent, ApiClient, ApiError, BaseObservation, CacheWarmer, CacheWarmingError, Chain, ChatPromptClient, Client, Config, ConfigurationError, Embedding, Error, Evaluator, Event, Generation, Guardrail, NotFoundError, PromptCache, RailsCacheAdapter, Retriever, ScoreClient, Span, SpanProcessor, TextPromptClient, Tool, UnauthorizedError

Constant Summary collapse

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.3.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



54
55
56
# File 'lib/langfuse.rb', line 54

def configuration
  @configuration ||= Config.new
end

Class Method Details

.clientClient

Returns the global singleton client

Returns:

  • (Client)

    the global client instance



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

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



68
69
70
71
72
73
74
75
# File 'lib/langfuse.rb', line 68

def configure
  yield(configuration)

  # Auto-initialize OpenTelemetry
  OtelSetup.setup(configuration)

  configuration
end

.create_score(name:, value:, trace_id: nil, observation_id: nil, comment: nil, metadata: nil, data_type: :numeric) ⇒ 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)

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

    Trace 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

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

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

Raises:

  • (ArgumentError)

    if validation fails



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/langfuse.rb', line 188

def create_score(name:, value:, trace_id: nil, observation_id: nil, comment: nil, metadata: nil,
                 data_type: :numeric)
  client.create_score(
    name: name,
    value: value,
    trace_id: trace_id,
    observation_id: observation_id,
    comment: comment,
    metadata: ,
    data_type: data_type
  )
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


262
263
264
# File 'lib/langfuse.rb', line 262

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



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

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

.observe(name, attrs = {}, as_type: :span, **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.)

Yields:

  • (observation)

    Optional block that receives the observation object

Yield Parameters:

Returns:

  • (BaseObservation, Object)

    The observation (or block return value if block given)



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/langfuse.rb', line 353

def observe(name, attrs = {}, as_type: :span, **kwargs, &block)
  # Merge positional attrs and keyword kwargs
  merged_attrs = attrs.to_h.merge(kwargs)
  observation = start_observation(name, merged_attrs, as_type: as_type)

  if block
    # Block-based API: auto-ends when block completes
    # Set context and execute block
    current_context = OpenTelemetry::Context.current
    result = OpenTelemetry::Context.with_current(
      OpenTelemetry::Trace.context_with_span(observation.otel_span, parent_context: current_context)
    ) do
      block.call(observation)
    end
    # Only end if not already ended (events auto-end in start_observation)
    observation.end unless as_type.to_s == OBSERVATION_TYPES[:event]
    result
  else
    # Stateful API - return observation
    # Events already auto-ended in start_observation
    observation
  end
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



154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/langfuse.rb', line 154

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)



269
270
271
272
273
274
275
276
277
278
# File 'lib/langfuse.rb', line 269

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



218
219
220
221
222
223
224
225
226
# File 'lib/langfuse.rb', line 218

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



244
245
246
247
248
249
250
251
252
# File 'lib/langfuse.rb', line 244

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



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

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

.start_observation(name, attrs = {}, as_type: :span, 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).

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)

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.)

  • 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)



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/langfuse.rb', line 301

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

  unless skip_validation || valid_observation_type?(as_type)
    valid_types = OBSERVATION_TYPES.values.sort.join(", ")
    raise ArgumentError, "Invalid observation type: #{type_str}. Valid types: #{valid_types}"
  end

  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
  )

  # Serialize attributes
  # Only set attributes if span is still recording (should always be true here, but guard for safety)
  if otel_span.recording?
    otel_attrs = OtelAttributes.create_observation_attributes(type_str, attrs.to_h)
    otel_attrs.each { |key, value| otel_span.set_attribute(key, value) }
  end

  # Wrap in appropriate class
  observation = wrap_otel_span(otel_span, type_str, otel_tracer, attributes: attrs)

  # Events auto-end immediately when created
  observation.end if type_str == OBSERVATION_TYPES[:event]

  observation
end