Module: LogBrew::OperationTracing
- Defined in:
- lib/logbrew/operation_tracing.rb
Overview
Explicit dependency spans for app-owned database, cache, and queue work.
Class Method Summary collapse
- .add_option(metadata, key, value) ⇒ Object
- .cache_operation(client, name, **options, &block) ⇒ Object
- .capture_operation(client, kind, name, options) ⇒ Object
- .capture_span(client, kind, name, context, started_at, options, error) ⇒ Object
- .child_context ⇒ Object
- .database_operation(client, name, **options, &block) ⇒ Object
- .duration_ms(started_at, options) ⇒ Object
- .event_id(kind, context, options) ⇒ Object
- .generate_span_id ⇒ Object
- .monotonic_time ⇒ Object
- .primitive_metadata_value?(value) ⇒ Boolean
- .queue_operation(client, name, **options, &block) ⇒ Object
- .read_option(options, key) ⇒ Object
- .sanitized_metadata(metadata) ⇒ Object
- .span_metadata(kind, options, error) ⇒ Object
- .timestamp(options) ⇒ Object
- .unsafe_metadata_key?(key) ⇒ Boolean
Class Method Details
.add_option(metadata, key, value) ⇒ Object
142 143 144 |
# File 'lib/logbrew/operation_tracing.rb', line 142 def add_option(, key, value) [key] = value if (value) && !(value.is_a?(String) && value.strip.empty?) end |
.cache_operation(client, name, **options, &block) ⇒ Object
41 42 43 |
# File 'lib/logbrew/operation_tracing.rb', line 41 def cache_operation(client, name, **, &block) capture_operation(client, "cache", name, , &block) end |
.capture_operation(client, kind, name, options) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/logbrew/operation_tracing.rb', line 49 def capture_operation(client, kind, name, ) raise SdkError.new("validation_error", "#{kind} operation block is required") unless block_given? Validation.require_non_empty("#{kind} operation name", name) started_at = monotonic_time context = child_context error = nil result = nil Trace.with_context(context) do begin result = yield context rescue StandardError => captured error = captured end end capture_span(client, kind, name, context, started_at, , error) raise error if error result end |
.capture_span(client, kind, name, context, started_at, options, error) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/logbrew/operation_tracing.rb', line 72 def capture_span(client, kind, name, context, started_at, , error) client.span( event_id(kind, context, ), (), { name: "#{kind}.operation:#{name}", traceId: context.trace_id, spanId: context.span_id, parentSpanId: context.parent_span_id, status: error ? "error" : "ok", durationMs: duration_ms(started_at, ), metadata: (kind, , error) } ) rescue StandardError => capture_error on_error = read_option(, :on_error) begin on_error.call(capture_error) if on_error.respond_to?(:call) rescue StandardError nil end end |
.child_context ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/logbrew/operation_tracing.rb', line 95 def child_context parent = Trace.current return Trace.create_root unless parent Trace.create( trace_id: parent.trace_id, span_id: generate_span_id, parent_span_id: parent.span_id, trace_flags: parent.trace_flags ) end |
.database_operation(client, name, **options, &block) ⇒ Object
37 38 39 |
# File 'lib/logbrew/operation_tracing.rb', line 37 def database_operation(client, name, **, &block) capture_operation(client, "database", name, , &block) end |
.duration_ms(started_at, options) ⇒ Object
161 162 163 164 165 166 |
# File 'lib/logbrew/operation_tracing.rb', line 161 def duration_ms(started_at, ) configured = read_option(, :duration_ms) return configured unless configured.nil? ((monotonic_time - started_at) * 1000.0).round(3) end |
.event_id(kind, context, options) ⇒ Object
150 151 152 |
# File 'lib/logbrew/operation_tracing.rb', line 150 def event_id(kind, context, ) read_option(, :event_id) || "ruby_#{kind}_span_#{context.span_id}" end |
.generate_span_id ⇒ Object
172 173 174 175 176 177 |
# File 'lib/logbrew/operation_tracing.rb', line 172 def generate_span_id loop do value = SecureRandom.hex(8) return value unless value.delete("0").empty? end end |
.monotonic_time ⇒ Object
168 169 170 |
# File 'lib/logbrew/operation_tracing.rb', line 168 def monotonic_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end |
.primitive_metadata_value?(value) ⇒ Boolean
135 136 137 138 139 140 |
# File 'lib/logbrew/operation_tracing.rb', line 135 def (value) return true if value.nil? || value == true || value == false return true if value.is_a?(String) || value.is_a?(Integer) value.is_a?(Float) && value.finite? end |
.queue_operation(client, name, **options, &block) ⇒ Object
45 46 47 |
# File 'lib/logbrew/operation_tracing.rb', line 45 def queue_operation(client, name, **, &block) capture_operation(client, "queue", name, , &block) end |
.read_option(options, key) ⇒ Object
146 147 148 |
# File 'lib/logbrew/operation_tracing.rb', line 146 def read_option(, key) [key] || [key.to_s] end |
.sanitized_metadata(metadata) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/logbrew/operation_tracing.rb', line 117 def () return {} if .nil? raise SdkError.new("validation_error", "operation metadata must be an object") unless .is_a?(Hash) .each_with_object({}) do |(key, value), copied| normalized_key = key.to_s next if normalized_key.strip.empty? next if (normalized_key) next unless (value) copied[normalized_key] = value end end |
.span_metadata(kind, options, error) ⇒ Object
107 108 109 110 111 112 113 114 115 |
# File 'lib/logbrew/operation_tracing.rb', line 107 def (kind, , error) (read_option(, :metadata)).tap do || ["source"] = "#{kind}.operation" add_option(, "#{kind}.system", read_option(, :system)) add_option(, "#{kind}.operation", read_option(, :operation)) add_option(, "#{kind}.target", read_option(, :target)) ["exceptionType"] = error.class.name if error end end |
.timestamp(options) ⇒ Object
154 155 156 157 158 159 |
# File 'lib/logbrew/operation_tracing.rb', line 154 def () value = read_option(, :timestamp) return value unless value.nil? Time.now.utc.iso8601 end |
.unsafe_metadata_key?(key) ⇒ Boolean
131 132 133 |
# File 'lib/logbrew/operation_tracing.rb', line 131 def (key) UNSAFE_METADATA_PATTERNS.any? { |pattern| key.match?(pattern) } end |