Module: Braintrust::Trace
- Defined in:
- lib/braintrust/trace.rb,
lib/braintrust/trace/attachment.rb,
lib/braintrust/trace/span_filter.rb,
lib/braintrust/trace/span_exporter.rb,
lib/braintrust/trace/span_processor.rb,
lib/braintrust/contrib/openai/deprecated.rb,
lib/braintrust/contrib/ruby_llm/deprecated.rb,
lib/braintrust/contrib/anthropic/deprecated.rb,
lib/braintrust/contrib/ruby_openai/deprecated.rb
Defined Under Namespace
Modules: AlexRudall, Anthropic, Contrib, OpenAI, SpanFilter Classes: Attachment, SpanExporter, SpanProcessor
Class Attribute Summary collapse
-
.exit_hook_registered ⇒ Object
Returns the value of attribute exit_hook_registered.
Class Method Summary collapse
-
.build_filters(config) ⇒ Array<Proc>
Build filters array from config.
- .enable(tracer_provider, state: nil, exporter: nil, config: nil) ⇒ Object
-
.flush_spans ⇒ Boolean
Flush buffered spans from the global tracer provider.
-
.permalink(span) ⇒ String
Generate a permalink URL for a span to view in the Braintrust UI Returns an empty string if the permalink cannot be generated.
-
.register_exit_hook ⇒ Object
Register an at_exit hook to flush spans before program exit.
-
.setup(state, tracer_provider = nil, exporter: nil) ⇒ void
Set up OpenTelemetry tracing with Braintrust.
Class Attribute Details
.exit_hook_registered ⇒ Object
Returns the value of attribute exit_hook_registered.
17 18 19 |
# File 'lib/braintrust/trace.rb', line 17 def exit_hook_registered @exit_hook_registered end |
Class Method Details
.build_filters(config) ⇒ Array<Proc>
Build filters array from config
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/braintrust/trace.rb', line 126 def self.build_filters(config) filters = [] # Add custom filters first (they have priority) if config&.span_filter_funcs&.any? filters.concat(config.span_filter_funcs) end # Add AI filter if enabled if config&.filter_ai_spans filters << SpanFilter.method(:ai_filter) end filters end |
.enable(tracer_provider, state: nil, exporter: nil, config: nil) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/braintrust/trace.rb', line 84 def self.enable(tracer_provider, state: nil, exporter: nil, config: nil) state ||= Braintrust.current_state raise Error, "No state available" unless state # Get config from state if available config ||= state.respond_to?(:config) ? state.config : nil # Create OTLP HTTP exporter unless override provided exporter ||= SpanExporter.new( endpoint: "#{state.api_url}/otel/v1/traces", api_key: state.api_key ) # Use SimpleSpanProcessor for InMemorySpanExporter (testing), BatchSpanProcessor for production span_processor = if exporter.is_a?(OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter) OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(exporter) else OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter) end # Build filters array from config filters = build_filters(config) # Wrap span processor in our custom span processor to add Braintrust attributes and filters processor = SpanProcessor.new(span_processor, state, filters) # Register with tracer provider tracer_provider.add_span_processor(processor) # Console debug if enabled if ENV["BRAINTRUST_ENABLE_TRACE_CONSOLE_LOG"] console_exporter = OpenTelemetry::SDK::Trace::Export::ConsoleSpanExporter.new console_processor = OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(console_exporter) tracer_provider.add_span_processor(console_processor) end self end |
.flush_spans ⇒ Boolean
Flush buffered spans from the global tracer provider. Forces immediate export of any spans buffered by BatchSpanProcessor.
70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/braintrust/trace.rb', line 70 def self.flush_spans provider = OpenTelemetry.tracer_provider return false unless provider.respond_to?(:force_flush) Log.debug("Flushing spans") begin provider.force_flush true rescue => e Log.debug("Failed to flush spans: #{e.}") false end end |
.permalink(span) ⇒ String
Generate a permalink URL for a span to view in the Braintrust UI Returns an empty string if the permalink cannot be generated
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/braintrust/trace.rb', line 146 def self.permalink(span) return "" if span.nil? # Extract required attributes from span span_context = span.context trace_id = span_context.hex_trace_id span_id = span_context.hex_span_id # Get Braintrust attributes attributes = span.attributes if span.respond_to?(:attributes) unless attributes Log.error("Span does not support attributes") return "" end app_url = attributes[SpanProcessor::APP_URL_ATTR_KEY] org_name = attributes[SpanProcessor::ORG_ATTR_KEY] parent = attributes[SpanProcessor::PARENT_ATTR_KEY] # Validate required attributes unless app_url Log.error("Missing required attribute: #{SpanProcessor::APP_URL_ATTR_KEY}") return "" end unless org_name Log.error("Missing required attribute: #{SpanProcessor::ORG_ATTR_KEY}") return "" end unless parent Log.error("Missing required attribute: #{SpanProcessor::PARENT_ATTR_KEY}") return "" end # Parse parent to determine URL format parent_type, parent_id = parent.split(":", 2) unless parent_type && parent_id Log.error("Invalid parent format: #{parent}") return "" end # Build the permalink URL based on parent type if parent_type == "experiment_id" # For experiments: {app_url}/app/{org}/object?object_type=experiment&object_id={experiment_id}&r={trace_id}&s={span_id} "#{app_url}/app/#{org_name}/object?object_type=experiment&object_id=#{parent_id}&r=#{trace_id}&s=#{span_id}" else # For projects: {app_url}/app/{org}/p/{project}/logs?r={trace_id}&s={span_id} # parent_type is typically "project_name" "#{app_url}/app/#{org_name}/p/#{parent_id}/logs?r=#{trace_id}&s=#{span_id}" end rescue => e Log.error("Failed to generate permalink: #{e.}") "" end |
.register_exit_hook ⇒ Object
Register an at_exit hook to flush spans before program exit. This ensures buffered spans in BatchSpanProcessor are exported. Only registers once, and only for the global tracer provider. Controlled by BRAINTRUST_FLUSH_ON_EXIT env var (default: true).
58 59 60 61 62 63 64 65 |
# File 'lib/braintrust/trace.rb', line 58 def self.register_exit_hook return if @exit_hook_registered return unless Internal::Env.flush_on_exit @exit_hook_registered = true at_exit { flush_spans } Log.debug("Registered at_exit hook for span flushing") end |
.setup(state, tracer_provider = nil, exporter: nil) ⇒ void
This method returns an undefined value.
Set up OpenTelemetry tracing with Braintrust
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/braintrust/trace.rb', line 25 def self.setup(state, tracer_provider = nil, exporter: nil) if tracer_provider # Use the explicitly provided tracer provider # DO NOT set as global - user is managing it themselves Log.debug("Using explicitly provided OpenTelemetry tracer provider") else # Check if global tracer provider is already a real TracerProvider current_provider = OpenTelemetry.tracer_provider if current_provider.is_a?(OpenTelemetry::SDK::Trace::TracerProvider) # Use existing provider Log.debug("Using existing OpenTelemetry tracer provider") tracer_provider = current_provider else # Create new provider and set as global tracer_provider = OpenTelemetry::SDK::Trace::TracerProvider.new OpenTelemetry.tracer_provider = tracer_provider Log.debug("Created OpenTelemetry tracer provider") end # Register at_exit hook for global provider (only once) register_exit_hook end # Enable Braintrust tracing (adds span processor) config = state.config enable(tracer_provider, state: state, config: config, exporter: exporter) end |