Module: BrainzLab::Pulse
- Defined in:
- lib/brainzlab/pulse.rb,
lib/brainzlab/pulse/client.rb,
lib/brainzlab/pulse/tracer.rb,
lib/brainzlab/pulse/propagation.rb,
lib/brainzlab/pulse/provisioner.rb,
lib/brainzlab/pulse/instrumentation.rb
Defined Under Namespace
Modules: Propagation Classes: Client, Instrumentation, Provisioner, Tracer
Class Method Summary collapse
-
.child_context ⇒ Object
Create a child propagation context for a new span.
- .client ⇒ Object
- .counter(name, value = 1, tags: {}) ⇒ Object
- .ensure_provisioned! ⇒ Object
-
.extract(headers) ⇒ Propagation::Context?
Distributed tracing: extract trace context from incoming headers.
-
.extract!(headers) ⇒ Propagation::Context?
Distributed tracing: extract and set as current context.
-
.finish_trace(error: false, error_class: nil, error_message: nil) ⇒ Object
Finish current trace.
-
.gauge(name, value, tags: {}) ⇒ Object
Convenience methods for metrics.
- .histogram(name, value, tags: {}) ⇒ Object
-
.inject(headers, format: :w3c) ⇒ Hash
Distributed tracing: inject trace context into outgoing headers.
-
.propagation_context ⇒ Object
Get current propagation context.
- .provisioner ⇒ Object
-
.record_metric(name, value:, kind: 'gauge', tags: {}) ⇒ Object
Record a custom metric.
-
.record_span(name:, duration_ms:, category:, attributes: {}, timestamp: nil) ⇒ Object
Record a standalone span (used by brainzlab-rails for Rails instrumentation).
-
.record_trace(name, started_at:, ended_at:, kind: 'request', **attributes) ⇒ Object
Record a complete trace (for when you have all data upfront).
- .reset! ⇒ Object
-
.span(name, kind: 'custom', **data) ⇒ Object
Add a span to the current trace.
-
.start_trace(name, kind: 'custom', parent_context: nil, **attributes) ⇒ Object
Start a new trace.
- .tracer ⇒ Object
Class Method Details
.child_context ⇒ Object
Create a child propagation context for a new span
214 215 216 |
# File 'lib/brainzlab/pulse.rb', line 214 def child_context Propagation.child_context end |
.client ⇒ Object
173 174 175 |
# File 'lib/brainzlab/pulse.rb', line 173 def client @client ||= Client.new(BrainzLab.configuration) end |
.counter(name, value = 1, tags: {}) ⇒ Object
99 100 101 |
# File 'lib/brainzlab/pulse.rb', line 99 def counter(name, value = 1, tags: {}) record_metric(name, value: value, kind: 'counter', tags: ) end |
.ensure_provisioned! ⇒ Object
158 159 160 161 162 163 |
# File 'lib/brainzlab/pulse.rb', line 158 def ensure_provisioned! return if @provisioned @provisioned = true provisioner.ensure_project! end |
.extract(headers) ⇒ Propagation::Context?
Distributed tracing: extract trace context from incoming headers
197 198 199 |
# File 'lib/brainzlab/pulse.rb', line 197 def extract(headers) Propagation.extract(headers) end |
.extract!(headers) ⇒ Propagation::Context?
Distributed tracing: extract and set as current context
204 205 206 |
# File 'lib/brainzlab/pulse.rb', line 204 def extract!(headers) Propagation.extract!(headers) end |
.finish_trace(error: false, error_class: nil, error_message: nil) ⇒ Object
Finish current trace
32 33 34 35 36 |
# File 'lib/brainzlab/pulse.rb', line 32 def finish_trace(error: false, error_class: nil, error_message: nil) return unless enabled? tracer.finish_trace(error: error, error_class: error_class, error_message: ) end |
.gauge(name, value, tags: {}) ⇒ Object
Convenience methods for metrics
95 96 97 |
# File 'lib/brainzlab/pulse.rb', line 95 def gauge(name, value, tags: {}) record_metric(name, value: value, kind: 'gauge', tags: ) end |
.histogram(name, value, tags: {}) ⇒ Object
103 104 105 |
# File 'lib/brainzlab/pulse.rb', line 103 def histogram(name, value, tags: {}) record_metric(name, value: value, kind: 'histogram', tags: ) end |
.inject(headers, format: :w3c) ⇒ Hash
Distributed tracing: inject trace context into outgoing headers
189 190 191 192 |
# File 'lib/brainzlab/pulse.rb', line 189 def inject(headers, format: :w3c) ctx = Propagation.current || create_propagation_context Propagation.inject(headers, context: ctx, format: format) end |
.propagation_context ⇒ Object
Get current propagation context
209 210 211 |
# File 'lib/brainzlab/pulse.rb', line 209 def propagation_context Propagation.current end |
.provisioner ⇒ Object
165 166 167 |
# File 'lib/brainzlab/pulse.rb', line 165 def provisioner @provisioner ||= Provisioner.new(BrainzLab.configuration) end |
.record_metric(name, value:, kind: 'gauge', tags: {}) ⇒ Object
Record a custom metric
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/brainzlab/pulse.rb', line 65 def record_metric(name, value:, kind: 'gauge', tags: {}) return unless enabled? payload = { name: name, value: value, kind: kind, timestamp: Time.now.utc.iso8601(3), tags: } # In development mode, log locally instead of sending to server if BrainzLab.configuration.development_mode? Development.record(service: :pulse, event_type: 'metric', payload: payload) return end ensure_provisioned! return unless BrainzLab.configuration.pulse_valid? if BrainzLab.instrumenting? # During instrumentation, send in background thread to avoid # blocking the host app with synchronous HTTP Thread.new { client.send_metric(payload) } else client.send_metric(payload) end end |
.record_span(name:, duration_ms:, category:, attributes: {}, timestamp: nil) ⇒ Object
Record a standalone span (used by brainzlab-rails for Rails instrumentation)
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/brainzlab/pulse.rb', line 113 def record_span(name:, duration_ms:, category:, attributes: {}, timestamp: nil) return unless enabled? ensure_provisioned! return unless BrainzLab.configuration.pulse_valid? # Parse timestamp or use current time started_at = if Time.parse() rescue Time.now.utc else Time.now.utc end span_data = { span_id: SecureRandom.uuid, name: name, kind: category, started_at: started_at, ended_at: started_at, # Same as started_at since we only have duration duration_ms: duration_ms, error: false, data: attributes } # If there's an active trace, add the span to it (will be sent with finish_trace) # Otherwise, send it directly to the API as a standalone span if tracer.current_trace tracer.current_spans << span_data else # Send as standalone span (backward compatibility) api_span_data = { name: name, category: category, duration_ms: duration_ms, timestamp: || Time.now.utc.iso8601(3), attributes: attributes, environment: BrainzLab.configuration.environment, service: BrainzLab.configuration.service, host: BrainzLab.configuration.host, request_id: Context.current.request_id }.compact client.send_span(api_span_data) end end |
.record_trace(name, started_at:, ended_at:, kind: 'request', **attributes) ⇒ Object
Record a complete trace (for when you have all data upfront)
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/brainzlab/pulse.rb', line 47 def record_trace(name, started_at:, ended_at:, kind: 'request', **attributes) return unless enabled? payload = build_trace_payload(name, kind, started_at, ended_at, attributes) # In development mode, log locally instead of sending to server if BrainzLab.configuration.development_mode? Development.record(service: :pulse, event_type: 'trace', payload: payload) return end ensure_provisioned! return unless BrainzLab.configuration.pulse_valid? client.send_trace(payload) end |
.reset! ⇒ Object
177 178 179 180 181 182 183 |
# File 'lib/brainzlab/pulse.rb', line 177 def reset! @client = nil @tracer = nil @provisioner = nil @provisioned = false Propagation.clear! end |
.span(name, kind: 'custom', **data) ⇒ Object
Add a span to the current trace
39 40 41 42 43 44 |
# File 'lib/brainzlab/pulse.rb', line 39 def span(name, kind: 'custom', **data, &) return yield unless enabled? return yield unless tracer.current_trace tracer.span(name, kind: kind, **data, &) end |
.start_trace(name, kind: 'custom', parent_context: nil, **attributes) ⇒ Object
Start a new trace
16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/brainzlab/pulse.rb', line 16 def start_trace(name, kind: 'custom', parent_context: nil, **attributes) return nil unless enabled? ensure_provisioned! return nil unless BrainzLab.configuration.pulse_valid? # Use parent context trace_id if provided (distributed tracing) if parent_context&.valid? attributes[:parent_trace_id] = parent_context.trace_id attributes[:parent_span_id] = parent_context.span_id end tracer.start_trace(name, kind: kind, **attributes) end |
.tracer ⇒ Object
169 170 171 |
# File 'lib/brainzlab/pulse.rb', line 169 def tracer @tracer ||= Tracer.new(BrainzLab.configuration, client) end |