Class: Langfuse::BaseObservation Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/langfuse/observations.rb

Overview

This class is abstract.

Subclass and pass type: to super to create concrete observation types

Base class for all Langfuse observation wrappers.

Provides unified functionality for spans, generations, events, and specialized observation types. Wraps OpenTelemetry spans with Langfuse-specific functionality. Uses unified ‘start_observation()` method with `as_type` parameter, aligning with langfuse-js architecture.

Examples:

Block-based API (auto-ends)

Langfuse.observe("parent-operation", input: { query: "test" }) do |span|
  # Child span
  span.start_observation("data-processing", input: { step: "fetch" }) do |child|
    result = fetch_data
    child.update(output: result)
  end

  # Child generation (LLM call)
  span.start_observation("llm-call", { model: "gpt-4", input: [{ role: "user", content: "Hello" }] }, as_type: :generation) do |gen|
    response = call_llm
    gen.update(output: response, usage_details: { prompt_tokens: 100, completion_tokens: 50 })
  end
end

Stateful API (manual end)

span = Langfuse.start_observation("parent-operation", { input: { query: "test" } })

# Child span
child_span = span.start_observation("data-validation", { input: { data: result } })
validate_data
child_span.update(output: { valid: true })
child_span.end

# Child generation (LLM call)
gen = span.start_observation("llm-summary", {
  model: "gpt-3.5-turbo",
  input: [{ role: "user", content: "Summarize" }]
}, as_type: :generation)
summary = call_llm
gen.update(output: summary, usage_details: { prompt_tokens: 50, completion_tokens: 25 })
gen.end

span.end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(otel_span, otel_tracer, attributes: nil, type: nil) ⇒ BaseObservation

Returns a new instance of BaseObservation.

Parameters:

  • otel_span (OpenTelemetry::SDK::Trace::Span)

    The underlying OTel span

  • otel_tracer (OpenTelemetry::SDK::Trace::Tracer)

    The OTel tracer

  • attributes (Hash, Types::SpanAttributes, Types::GenerationAttributes, nil) (defaults to: nil)

    Optional initial attributes

  • type (String) (defaults to: nil)

    Observation type (e.g., “span”, “generation”, “event”)



74
75
76
77
78
79
80
81
82
83
# File 'lib/langfuse/observations.rb', line 74

def initialize(otel_span, otel_tracer, attributes: nil, type: nil)
  @otel_span = otel_span
  @otel_tracer = otel_tracer
  @type = type || raise(ArgumentError, "type must be provided")

  # Set initial attributes if provided
  return unless attributes

  update_observation_attributes(attributes.to_h)
end

Instance Attribute Details

#otel_spanOpenTelemetry::SDK::Trace::Span (readonly)

Returns The underlying OTel span.

Returns:

  • (OpenTelemetry::SDK::Trace::Span)

    The underlying OTel span



62
63
64
# File 'lib/langfuse/observations.rb', line 62

def otel_span
  @otel_span
end

#otel_tracerOpenTelemetry::SDK::Trace::Tracer (readonly)

Returns The OTel tracer.

Returns:

  • (OpenTelemetry::SDK::Trace::Tracer)

    The OTel tracer



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

def otel_tracer
  @otel_tracer
end

#typeString (readonly)

Returns Observation type (e.g., “span”, “generation”, “event”).

Returns:

  • (String)

    Observation type (e.g., “span”, “generation”, “event”)



68
69
70
# File 'lib/langfuse/observations.rb', line 68

def type
  @type
end

Instance Method Details

#current_spanOpenTelemetry::SDK::Trace::Span

Returns:

  • (OpenTelemetry::SDK::Trace::Span)


208
209
210
# File 'lib/langfuse/observations.rb', line 208

def current_span
  @otel_span
end

#end(end_time: nil) ⇒ void

This method returns an undefined value.

Ends the observation span.

Parameters:

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

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



109
110
111
# File 'lib/langfuse/observations.rb', line 109

def end(end_time: nil)
  @otel_span.finish(end_timestamp: end_time)
end

#event(name:, input: nil, level: "default") ⇒ void

This method returns an undefined value.

Adds an event to this observation’s span.

Parameters:

  • name (String)

    Event name

  • input (Object, nil) (defaults to: nil)

    Optional event data

  • level (String) (defaults to: "default")

    Log level (debug, default, warning, error)



198
199
200
201
202
203
204
205
# File 'lib/langfuse/observations.rb', line 198

def event(name:, input: nil, level: "default")
  attributes = {
    "langfuse.observation.input" => input&.to_json,
    "langfuse.observation.level" => level
  }.compact

  @otel_span.add_event(name, attributes: attributes)
end

#idString

Returns Hex-encoded span ID (16 hex characters).

Returns:

  • (String)

    Hex-encoded span ID (16 hex characters)



86
87
88
# File 'lib/langfuse/observations.rb', line 86

def id
  @otel_span.context.span_id.unpack1("H*")
end

#input=(value) ⇒ void

This method returns an undefined value.

Sets observation-level input attributes.

Parameters:

  • value (Object)

    Input value (will be JSON-encoded)



168
169
170
# File 'lib/langfuse/observations.rb', line 168

def input=(value)
  update_observation_attributes(input: value)
end

#level=(value) ⇒ void

This method returns an undefined value.

Parameters:

  • value (String)

    Level (DEBUG, DEFAULT, WARNING, ERROR)



188
189
190
# File 'lib/langfuse/observations.rb', line 188

def level=(value)
  update_observation_attributes(level: value)
end

#metadata=(value) ⇒ void

This method returns an undefined value.

Parameters:

  • value (Hash)

    Metadata hash (expanded into individual langfuse.observation.metadata.* attributes)



182
183
184
# File 'lib/langfuse/observations.rb', line 182

def metadata=(value)
  update_observation_attributes(metadata: value)
end

#output=(value) ⇒ void

This method returns an undefined value.

Sets observation-level output attributes.

Parameters:

  • value (Object)

    Output value (will be JSON-encoded)



176
177
178
# File 'lib/langfuse/observations.rb', line 176

def output=(value)
  update_observation_attributes(output: value)
end

#score_trace(name:, value:, comment: nil, metadata: nil, data_type: :numeric) ⇒ Hash

Create a score for the trace this observation belongs to

Parameters:

  • name (String)

    score name

  • value (Numeric, String, Boolean)

    score value

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

    optional comment

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

    optional metadata

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

    one of :numeric, :boolean, :categorical

Returns:

  • (Hash)

    created score data from the API



220
221
222
223
224
225
226
227
228
229
# File 'lib/langfuse/observations.rb', line 220

def score_trace(name:, value:, comment: nil, metadata: nil, data_type: :numeric)
  Langfuse.create_score(
    name: name,
    value: value,
    trace_id: trace_id,
    comment: comment,
    metadata: ,
    data_type: data_type
  )
end

#start_observation(name, attrs = {}, as_type: :span) {|observation| ... } ⇒ BaseObservation, Object

Creates a child observation within this observation’s context.

Supports block-based (auto-ends) and stateful (manual end) APIs. Events auto-end when created without a block.

Parameters:

  • name (String)

    Descriptive name for the child 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.). Defaults to ‘:span`.

Yields:

  • (observation)

    Optional block that receives the observation object

Returns:

  • (BaseObservation, Object)

    The child observation (or block return value if block given)



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/langfuse/observations.rb', line 134

def start_observation(name, attrs = {}, as_type: :span, &block)
  # Call module-level factory with parent context
  # Skip validation to allow unknown types to fall back to Span
  child = Langfuse.start_observation(
    name,
    attrs,
    as_type: as_type,
    parent_span_context: @otel_span.context,
    skip_validation: true
  )

  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(child.otel_span, parent_context: current_context)
    ) do
      block.call(child)
    end
    # Only end if not already ended (events auto-end in start_observation)
    child.end unless as_type.to_s == OBSERVATION_TYPES[:event]
    result
  else
    # Stateful API - return observation
    # Events already auto-ended in start_observation
    child
  end
end

#trace_idString

Returns Hex-encoded trace ID (32 hex characters).

Returns:

  • (String)

    Hex-encoded trace ID (32 hex characters)



91
92
93
# File 'lib/langfuse/observations.rb', line 91

def trace_id
  @otel_span.context.trace_id.unpack1("H*")
end

#trace_urlString

Returns URL to view this trace in Langfuse UI.

Examples:

span = Langfuse.observe("operation") do |obs|
  puts "View trace: #{obs.trace_url}"
end

Returns:

  • (String)

    URL to view this trace in Langfuse UI



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

def trace_url
  Langfuse.client.trace_url(trace_id)
end

#update_trace(attrs) ⇒ self

Updates trace-level attributes (user_id, session_id, tags, etc.) for the entire trace.

Parameters:

Returns:

  • (self)


117
118
119
120
121
122
123
# File 'lib/langfuse/observations.rb', line 117

def update_trace(attrs)
  return self unless @otel_span.recording?

  otel_attrs = OtelAttributes.create_trace_attributes(attrs.to_h)
  otel_attrs.each { |key, value| @otel_span.set_attribute(key, value) }
  self
end