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.



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

def initialize(transport, config, logger)
  @transport = transport
  @config = config
  @logger = logger
  @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

#current_span_idObject



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

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

#current_trace_idObject



24
25
26
# File 'lib/allstak/modules/tracing.rb', line 24

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)


48
49
50
51
52
53
54
55
# File 'lib/allstak/modules/tracing.rb', line 48

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

#flushObject



96
97
98
# File 'lib/allstak/modules/tracing.rb', line 96

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`).



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/allstak/modules/tracing.rb', line 83

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



37
38
39
40
41
# File 'lib/allstak/modules/tracing.rb', line 37

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

#set_trace_id(trace_id) ⇒ Object



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

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

#shutdownObject



100
101
102
# File 'lib/allstak/modules/tracing.rb', line 100

def shutdown
  @buffer.shutdown
end

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



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/allstak/modules/tracing.rb', line 57

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