Class: AllStak::Modules::Tracing

Inherits:
Object
  • Object
show all
Defined in:
lib/allstak/modules/tracing.rb

Overview

Distributed tracing — spans with parent-child hierarchy via Thread-local state.

Constant Summary collapse

PATH =
"/ingest/v1/spans".freeze
VALID_STATUSES =
%w[ok error timeout].freeze

Instance Method Summary collapse

Constructor Details

#initialize(transport, config, logger) ⇒ Tracing

Returns a new instance of Tracing.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/allstak/modules/tracing.rb', line 12

def initialize(transport, config, logger)
  @transport = transport
  @config = config
  @logger = logger
  @captured_count = 0
  @dropped_count = 0
  @buffer = Transport::FlushBuffer.new(
    name: "tracing",
    max_size: config.buffer_size,
    interval_ms: config.flush_interval_ms,
    flush_proc: method(:flush_batch),
    logger: logger
  )
end

Instance Method Details

#active_span_countObject



124
125
126
127
128
129
# File 'lib/allstak/modules/tracing.rb', line 124

def active_span_count
  stack = Thread.current[:allstak_span_stack]
  stack.respond_to?(:length) ? stack.length : 0
rescue StandardError
  0
end

#active_trace_countObject



131
132
133
134
135
# File 'lib/allstak/modules/tracing.rb', line 131

def active_trace_count
  Thread.current[:allstak_trace_id].nil? ? 0 : 1
rescue StandardError
  0
end

#buffer_countObject



112
113
114
# File 'lib/allstak/modules/tracing.rb', line 112

def buffer_count
  @buffer.count
end

#captured_countObject



120
121
122
# File 'lib/allstak/modules/tracing.rb', line 120

def captured_count
  @captured_count
end

#current_span_idObject



40
41
42
43
# File 'lib/allstak/modules/tracing.rb', line 40

def current_span_id
  stack = Thread.current[:allstak_span_stack]
  stack&.last
end

#current_trace_idObject



27
28
29
# File 'lib/allstak/modules/tracing.rb', line 27

def current_trace_id
  Thread.current[:allstak_trace_id] ||= SecureRandom.hex(16)
end

#current_trace_sampled?Boolean

Sampling decision for the CURRENT trace. Decided once (at the first span of the trace) and cached thread-locally so every span and the propagated traceparent flag agree. When ‘traces_sample_rate` is nil (the default), tracing is unsampled-mode-off: everything is kept and the traceparent sampled flag stays “01” (historical behavior).

Returns:

  • (Boolean)


56
57
58
59
60
61
62
63
# File 'lib/allstak/modules/tracing.rb', line 56

def current_trace_sampled?
  decided = Thread.current[:allstak_trace_sampled]
  return decided unless decided.nil?
  rate = @config.traces_sample_rate
  decided = rate.nil? ? true : Sampling.sampled?(rate)
  Thread.current[:allstak_trace_sampled] = decided
  decided
end

#dropped_countObject



116
117
118
# File 'lib/allstak/modules/tracing.rb', line 116

def dropped_count
  @dropped_count + @buffer.dropped_count
end

#flushObject



104
105
106
# File 'lib/allstak/modules/tracing.rb', line 104

def flush
  @buffer.flush
end

#in_span(operation, description: "", tags: nil) ⇒ Object

Block-form helper: automatically finishes the span on return, on raise, or on non-local flow (e.g. Sinatra’s ‘throw :halt`).



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/allstak/modules/tracing.rb', line 91

def in_span(operation, description: "", tags: nil)
  span = start_span(operation, description: description, tags: tags)
  status = "ok"
  begin
    return yield(span)
  rescue => e
    status = "error"
    raise
  ensure
    span.finish(status) unless span.finished?
  end
end

#reset_traceObject



45
46
47
48
49
# File 'lib/allstak/modules/tracing.rb', line 45

def reset_trace
  Thread.current[:allstak_trace_id] = nil
  Thread.current[:allstak_span_stack] = nil
  Thread.current[:allstak_trace_sampled] = nil
end

#set_parent_span_id(span_id) ⇒ Object



35
36
37
38
# File 'lib/allstak/modules/tracing.rb', line 35

def set_parent_span_id(span_id)
  return unless AllStak::Propagation.valid_span_id?(span_id)
  Thread.current[:allstak_span_stack] = [span_id.to_s.downcase]
end

#set_trace_id(trace_id) ⇒ Object



31
32
33
# File 'lib/allstak/modules/tracing.rb', line 31

def set_trace_id(trace_id)
  Thread.current[:allstak_trace_id] = AllStak::Propagation.normalize_trace_id(trace_id)
end

#shutdownObject



108
109
110
# File 'lib/allstak/modules/tracing.rb', line 108

def shutdown
  @buffer.shutdown
end

#start_span(operation, description: "", tags: nil) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/allstak/modules/tracing.rb', line 65

def start_span(operation, description: "", tags: nil)
  trace_id = current_trace_id
  sampled = current_trace_sampled?
  span_id = SecureRandom.hex(8)
  parent = current_span_id || ""
  Thread.current[:allstak_span_stack] ||= []
  Thread.current[:allstak_span_stack] << span_id

  Span.new(
    trace_id: trace_id,
    span_id: span_id,
    parent_span_id: parent,
    operation: operation,
    description: description,
    service: @config.service_name,
    environment: @config.environment || "",
    release: (@config.respond_to?(:release) ? @config.release : nil) || "",
    tags: tags || {},
    start_time_millis: (Time.now.to_f * 1000).to_i,
    sampled: sampled,
    on_finish: method(:on_span_finish)
  )
end