Class: LLM::Tracer
- Inherits:
-
Object
- Object
- LLM::Tracer
- Defined in:
- lib/llm/tracer.rb,
lib/llm/tracer/multi.rb,
lib/llm/tracer/rescue.rb,
lib/llm/tracer/registry.rb
Overview
The LLM::Tracer is the superclass of all LLM tracers. It can be helpful for implementing instrumentation and hooking into the lifecycle of an LLM request. See LLM::Tracer::Telemetry, and LLM::Tracer::Logger for example tracer implementations.
Direct Known Subclasses
Defined Under Namespace
Modules: Rescue Classes: EnhancedLogger, Logger, Multi, Null, Registry, Telemetry
Instance Attribute Summary collapse
- #llm ⇒ LLM::Provider readonly
Class Method Summary collapse
-
.registry ⇒ LLM::Tracer::Registry
private
Returns the registry that counts the open scopes for each tracer.
-
.enter(tracer) ⇒ LLM::Tracer::Registry
private
Records that a scope was opened for a tracer.
-
.exit(tracer)
private
Records that a scope was closed for a tracer, and tells the tracer it is finished when it was the last one that was open.
-
.enhanced_logger(llm, **options) ⇒ LLM::Tracer::EnhancedLogger
Builds a EnhancedLogger for a provider.
-
.logger(llm, **options) ⇒ LLM::Tracer::Logger
Builds a Logger for a provider.
-
.telemetry(llm, **options) ⇒ LLM::Tracer::Telemetry
Builds a Telemetry for a provider.
-
.multi(llm, *tracers) ⇒ LLM::Tracer::Multi
Builds a Multi.
- .inherited(klass)
Instance Method Summary collapse
-
#consume_request_metadata ⇒ Hash
Consume and clear per-request metadata.
-
#initialize(llm, options = {}) ⇒ Tracer
constructor
A new instance of Tracer.
-
#on_exit
This method is called when a tracer exits a scope that has been opened by Provider#with_tracer.
-
#on_request_start(operation:, model: nil, inputs: nil, request_id:)
Called before an LLM provider request is executed.
-
#on_request_finish(operation:, res:, model: nil, span: nil, outputs: nil, metadata: nil, request_id:)
Called after an LLM provider request succeeds.
-
#on_request_error(ex:, span:, request_id:)
Called when an LLM provider request fails.
-
#on_tool_start(id:, name:, arguments:, model:)
Called before a local tool/function executes.
-
#on_tool_interrupt(ex:, span:, started_at:, finished_at:)
Called when a tool is interrupted.
-
#on_tool_finish(result:, span:, started_at:, finished_at:)
Called after a tool/function succeeds.
-
#on_tool_error(ex:, span:, started_at:, finished_at:)
Called when a local tool/function raises.
-
#on_interrupt(scope:, span: nil, request_id: nil)
This method is called when an agent receives an interrupt.
-
#start_trace(trace_group_id: nil, name: "llm", attributes: {}, metadata: nil) ⇒ self
Opens a trace group so subsequent LLM spans share the same OpenTelemetry trace_id (and appear as one trace in backends like Langfuse).
-
#stop_trace ⇒ self
Finishes the trace group started by #start_trace.
- #inspect ⇒ String
- #spans ⇒ Array
-
#flush! ⇒ nil
Flush the tracer.
-
#merge_extra(metadata: nil, inputs: nil, outputs: nil) ⇒ self
Merges extra attributes for the current trace/span.
-
#set_finish_metadata_proc(proc) ⇒ self
Optional: set a proc to supply metadata when the next chat span finishes.
-
#consume_extra_inputs ⇒ Hash
Returns and clears extra inputs for the next span.
-
#consume_extra_outputs ⇒ Hash
Returns and clears extra outputs for the current span.
-
#set_request_metadata(metadata) ⇒ nil
Store per-request metadata (e.g. user_input) to be consumed by tracers when starting the next span.
Constructor Details
#initialize(llm, options = {}) ⇒ Tracer
Returns a new instance of Tracer.
127 128 129 130 |
# File 'lib/llm/tracer.rb', line 127 def initialize(llm, = {}) @llm = llm @options = {} end |
Instance Attribute Details
Class Method Details
.registry ⇒ LLM::Tracer::Registry
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the registry that counts the open scopes for each tracer.
38 39 40 41 42 |
# File 'lib/llm/tracer.rb', line 38 def self.registry LLM.lock(:registry) do @registry ||= Registry.new end end |
.enter(tracer) ⇒ LLM::Tracer::Registry
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Records that a scope was opened for a tracer.
51 52 53 |
# File 'lib/llm/tracer.rb', line 51 def self.enter(tracer) registry.enter(tracer) end |
.exit(tracer)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Records that a scope was closed for a tracer, and tells the tracer it is finished when it was the last one that was open.
62 63 64 |
# File 'lib/llm/tracer.rb', line 62 def self.exit(tracer) registry.exit(tracer) end |
.enhanced_logger(llm, **options) ⇒ LLM::Tracer::EnhancedLogger
Builds a EnhancedLogger for a provider.
73 74 75 |
# File 'lib/llm/tracer.rb', line 73 def self.enhanced_logger(llm, **) EnhancedLogger.new(llm, **) end |
.logger(llm, **options) ⇒ LLM::Tracer::Logger
Builds a Logger for a provider.
85 86 87 |
# File 'lib/llm/tracer.rb', line 85 def self.logger(llm, **) Logger.new(llm, **) end |
.telemetry(llm, **options) ⇒ LLM::Tracer::Telemetry
Builds a Telemetry for a provider.
96 97 98 |
# File 'lib/llm/tracer.rb', line 96 def self.telemetry(llm, **) Telemetry.new(llm, **) end |
.multi(llm, *tracers) ⇒ LLM::Tracer::Multi
Builds a Multi
106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/llm/tracer.rb', line 106 def self.multi(llm, *tracers) Multi.new( *tracers.map do |tracer| if Class === tracer tracer.new(llm) else tracer end end ) end |
.inherited(klass)
This method returns an undefined value.
24 25 26 |
# File 'lib/llm/tracer.rb', line 24 def self.inherited(klass) klass.prepend Rescue end |
Instance Method Details
#consume_request_metadata ⇒ Hash
Consume and clear per-request metadata. Called by the telemetry tracer at span start.
432 433 434 435 436 437 |
# File 'lib/llm/tracer.rb', line 432 def key = data = thread[key] || {} thread[key] = nil data end |
#on_exit
This method returns an undefined value.
This method is called when a tracer exits a scope that has been opened by Provider#with_tracer.
It is unlikely you will ever use the Provider#with_tracer method directly but Agent uses it. An agent can have its own tracer, and it is scoped via Provider#with_tracer. When the tracer is done and Provider#with_tracer returns, this method (on_exit) is called.
A tracer that holds something - a file, a span, a connection pool - can use this method to release it. The Telemetry tracer uses this method to flush its queue of spans for export, and after the tracer has exited is a good time to do that.
150 151 152 |
# File 'lib/llm/tracer.rb', line 150 def on_exit raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_request_start(operation:, model: nil, inputs: nil, request_id:)
This method returns an undefined value.
Called before an LLM provider request is executed.
164 165 166 |
# File 'lib/llm/tracer.rb', line 164 def on_request_start(operation:, model: nil, inputs: nil, request_id:) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_request_finish(operation:, res:, model: nil, span: nil, outputs: nil, metadata: nil, request_id:)
This method returns an undefined value.
Called after an LLM provider request succeeds.
181 182 183 |
# File 'lib/llm/tracer.rb', line 181 def on_request_finish(operation:, res:, model: nil, span: nil, outputs: nil, metadata: nil, request_id:) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_request_error(ex:, span:, request_id:)
This method returns an undefined value.
Called when an LLM provider request fails.
192 193 194 |
# File 'lib/llm/tracer.rb', line 192 def on_request_error(ex:, span:, request_id:) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_tool_start(id:, name:, arguments:, model:)
This method returns an undefined value.
Called before a local tool/function executes.
207 208 209 |
# File 'lib/llm/tracer.rb', line 207 def on_tool_start(id:, name:, arguments:, model:) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_tool_interrupt(ex:, span:, started_at:, finished_at:)
This method returns an undefined value.
Called when a tool is interrupted.
This method is called once per tool - in a batch -
and only after all tools have been spawned in parallel
and then waited on sequentially. The *_at parameters
let you know when a tool has started and finished (as a
monotonic clock) since it cannot be inferred from the
time the method is called.
230 231 232 |
# File 'lib/llm/tracer.rb', line 230 def on_tool_interrupt(ex:, span:, started_at:, finished_at:) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_tool_finish(result:, span:, started_at:, finished_at:)
This method returns an undefined value.
Called after a tool/function succeeds.
This method is called once per tool - in a batch -
and only after all tools have been spawned in parallel
and then waited on sequentially. The *_at parameters
let you know when a tool has started and finished (as a
monotonic clock) since it cannot be inferred from the
time the method is called.
253 254 255 |
# File 'lib/llm/tracer.rb', line 253 def on_tool_finish(result:, span:, started_at:, finished_at:) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_tool_error(ex:, span:, started_at:, finished_at:)
This method provides the callback with an Function::Return object that encapsulates the exception a tool failed with. It does not provide an Exception object.
This method returns an undefined value.
Called when a local tool/function raises.
This method is called once per tool - in a batch -
and only after all tools have been spawned in parallel
and then waited on sequentially. The *_at parameters
let you know when a tool has started and finished (as a
monotonic clock) since it cannot be inferred from the
time the method is called.
283 284 285 |
# File 'lib/llm/tracer.rb', line 283 def on_tool_error(ex:, span:, started_at:, finished_at:) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#on_interrupt(scope:, span: nil, request_id: nil)
This is the last and final callback that is received as part of the interrupt process.
This method returns an undefined value.
This method is called when an agent receives
an interrupt. An interrupt can occur in different
scopes: :request, :agent, or :tool.
The :request scope provides a span and request ID,
and it can be used to close a request that was
interrupted. The other scopes (:tool, :agent)
occur in a context where there is no span or
request ID available.
309 310 311 |
# File 'lib/llm/tracer.rb', line 309 def on_interrupt(scope:, span: nil, request_id: nil) raise NotImplementedError, "#{self.class} does not implement '#{__method__}'" end |
#start_trace(trace_group_id: nil, name: "llm", attributes: {}, metadata: nil) ⇒ self
Opens a trace group so subsequent LLM spans share the same OpenTelemetry trace_id (and appear as one trace in backends like Langfuse). When +trace_group_id+ is a string, it is used to derive the trace_id.
328 329 330 |
# File 'lib/llm/tracer.rb', line 328 def start_trace(trace_group_id: nil, name: "llm", attributes: {}, metadata: nil) self end |
#stop_trace ⇒ self
Finishes the trace group started by #start_trace. Safe to call even if no trace is active.
336 337 338 |
# File 'lib/llm/tracer.rb', line 336 def stop_trace self end |
#inspect ⇒ String
342 343 344 |
# File 'lib/llm/tracer.rb', line 342 def inspect "#<#{LLM::Utils.object_id(self)} @llm=#{@llm.class} @tracer=#{@tracer.inspect}>" end |
#spans ⇒ Array
348 349 350 |
# File 'lib/llm/tracer.rb', line 348 def spans [] end |
#flush! ⇒ nil
This method is only implemented by the Telemetry tracer. It is a noop for other tracers.
Flush the tracer
358 359 360 |
# File 'lib/llm/tracer.rb', line 358 def flush! nil end |
#merge_extra(metadata: nil, inputs: nil, outputs: nil) ⇒ self
Merges extra attributes for the current trace/span. Used by applications (e.g. chatbot) to add metadata, span inputs, or span outputs to the next span or to the trace. No-op by default.
376 377 378 |
# File 'lib/llm/tracer.rb', line 376 def merge_extra(metadata: nil, inputs: nil, outputs: nil) self end |
#set_finish_metadata_proc(proc) ⇒ self
Optional: set a proc to supply metadata when the next chat span finishes. The proc is called with the response (res) and should return a Hash of metadata (e.g. { intent: "...", confidence: 1.0 }) to merge onto the span. Cleared after use. Used by apps to attach routing/intent that is only known after the response.
389 390 391 392 |
# File 'lib/llm/tracer.rb', line 389 def (proc) thread[FINISH_METADATA_PROC_KEY] = proc self end |
#consume_extra_inputs ⇒ Hash
Returns and clears extra inputs for the next span. Called by the telemetry tracer when starting a span. Subclasses can override to return stored inputs; default returns {}.
400 401 402 |
# File 'lib/llm/tracer.rb', line 400 def consume_extra_inputs {} end |
#consume_extra_outputs ⇒ Hash
Returns and clears extra outputs for the current span. Called by the telemetry tracer when finishing a span. Subclasses override to return fiber-local outputs; default returns {}.
410 411 412 |
# File 'lib/llm/tracer.rb', line 410 def consume_extra_outputs {} end |
#set_request_metadata(metadata) ⇒ nil
Store per-request metadata (e.g. user_input) to be consumed by tracers when starting the next span. Used for plain-text input.value / output.value.
420 421 422 423 424 425 426 |
# File 'lib/llm/tracer.rb', line 420 def () return nil unless && !.empty? key = current = thread[key] || {} thread[key] = current.merge(.compact) nil end |