Module: PlatformSdk::Observability::Langfuse

Defined in:
lib/platform_sdk/observability/langfuse.rb,
lib/platform_sdk/observability/langfuse/recorder.rb,
lib/platform_sdk/observability/langfuse/coercions.rb,
lib/platform_sdk/observability/langfuse/traceable.rb,
lib/platform_sdk/observability/langfuse/spec_support.rb,
lib/platform_sdk/observability/langfuse/configuration.rb,
lib/platform_sdk/observability/langfuse/sidekiq_lifecycle.rb,
lib/platform_sdk/observability/langfuse/null_span_exporter.rb

Defined Under Namespace

Modules: Coercions, Recorder, SidekiqLifecycle, SpecSupport, Traceable Classes: Configuration, ConfigurationError, Error, NullSpanExporter

Constant Summary collapse

OWNED_THREAD_LOCALS_KEY =
:platform_sdk_langfuse_owned_thread_locals

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.configurationObject (readonly)

Returns the value of attribute configuration.



19
20
21
# File 'lib/platform_sdk/observability/langfuse.rb', line 19

def configuration
  @configuration
end

Class Method Details

.clear_tracked_thread_locals!Object

Clear every thread-local registered via ‘track_thread_local` on this thread, then drop the registry itself. Called from the Traceable wrapper’s ‘ensure` block.



113
114
115
116
117
118
119
# File 'lib/platform_sdk/observability/langfuse.rb', line 113

def clear_tracked_thread_locals!
  owned = Thread.current[OWNED_THREAD_LOCALS_KEY]
  return unless owned

  owned.each { |k| Thread.current[k] = nil }
  Thread.current[OWNED_THREAD_LOCALS_KEY] = nil
end

.configure(app_name:, environment: nil, prompt_label: nil, exporter: nil) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
# File 'lib/platform_sdk/observability/langfuse.rb', line 21

def configure(app_name:, environment: nil, prompt_label: nil, exporter: nil)
  @configuration&.force_flush_and_shutdown
  @configuration = Configuration.new(
    app_name: app_name,
    environment: environment,
    prompt_label: prompt_label,
    exporter: exporter
  )
  SidekiqLifecycle.install! if @configuration.enabled?
  @configuration
end

.enabled?Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/platform_sdk/observability/langfuse.rb', line 33

def enabled?
  !@configuration.nil? && @configuration.enabled?
end

.record_generation(**kwargs) ⇒ Object



43
44
45
# File 'lib/platform_sdk/observability/langfuse.rb', line 43

def record_generation(**kwargs)
  Recorder.record_generation(**kwargs)
end

.reset!Object



85
86
87
88
89
# File 'lib/platform_sdk/observability/langfuse.rb', line 85

def reset!
  @configuration&.force_flush_and_shutdown
  @configuration = nil
  SidekiqLifecycle.reset!
end

.set_trace_output(value) ⇒ Object

Set the trace-level output on the active parent span. Application code calls this from inside a Traceable job (or any block running under an active span) to record a meaningful summary of the job’s result.

Why this is opt-in rather than auto-captured from ‘perform`’s return value: Sidekiq’s ‘perform` return is incidental — it’s often nil, an AR transaction callback array, or otherwise unrelated to anything a human reading a trace would find useful. Only the application knows what’s meaningful (e.g. a generated record’s ID).

Example:

class MyJob
  include Sidekiq::Job
  include PlatformSdk::Observability::Langfuse::Traceable

  def perform(args)
    component = generate_component(args)
    PlatformSdk::Observability::Langfuse.set_trace_output(
      { component_id: component.id, status: component.status }
    )
  end
end

No-ops when the SDK is disabled or no span is currently active. Never raises — observability failures must not break callers.



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

def set_trace_output(value)
  return unless enabled?

  span = OpenTelemetry::Trace.current_span
  return unless span.context.valid?

  span.set_attribute('langfuse.trace.output', Recorder.stringify(value))
rescue StandardError, SystemStackError => e
  OpenTelemetry.handle_error(message: "Langfuse set_trace_output failed: #{e.class}: #{e.message[0, 200]}")
  nil
end

.tracerObject



37
38
39
40
41
# File 'lib/platform_sdk/observability/langfuse.rb', line 37

def tracer
  return nil unless enabled?

  @configuration.tracer
end

.track_thread_local(*keys) ⇒ Object

Register thread-local keys that should be cleared at the next Traceable job boundary. Consumers call this when they store per-trace state on ‘Thread.current` (e.g. the ID of the last recorded message) so the value can’t leak into the next job that lands on this Sidekiq thread.

Example:

PlatformSdk::Observability::Langfuse.track_thread_local(:my_app_last_message_id)
Thread.current[:my_app_last_message_id] = msg.id

Compared to a name-prefix convention, this requires explicit opt-in (so consumers can’t accidentally have unrelated state zeroed) and is O(owned keys) instead of O(all thread locals).



104
105
106
107
108
# File 'lib/platform_sdk/observability/langfuse.rb', line 104

def track_thread_local(*keys)
  list = (Thread.current[OWNED_THREAD_LOCALS_KEY] ||= [])
  keys.each { |k| list << k unless list.include?(k) }
  nil
end