Class: CloseYourIt::TraceContext

Inherits:
Object
  • Object
show all
Defined in:
lib/closeyourit/trace_context.rb

Overview

Contesto di trace W3C (traceparent/tracestate, https://www.w3.org/TR/trace-context/). NON è un tracer: non apre span né misura tempi. È un "propagation bridge" minimale (il ticket: "Non costruire tracing custom completo") — adotta un contesto entrante valido facendo pass-through di trace-id/parent-id/flag, oppure ne genera uno root, e sa serializzarsi negli header d'uscita. Volutamente separato dai formati proprietari: sullo standard, senza dipendere da un vendor.

Constant Summary collapse

TRACEPARENT =

traceparent = version "-" trace-id "-" parent-id "-" trace-flags (55 char per la versione 00). rest cattura eventuali campi futuri: ammessi solo da versioni > 00 (forward-compat), vietati su 00.

/
  \A
  (?<version>[0-9a-f]{2})-
  (?<trace_id>[0-9a-f]{32})-
  (?<parent_id>[0-9a-f]{16})-
  (?<flags>[0-9a-f]{2})
  (?<rest>-.*)?
  \z
/x
FORBIDDEN_VERSION =
"ff"
CURRENT_VERSION =
"00"
ZERO_TRACE_ID =
("0" * 32).freeze
ZERO_PARENT_ID =
("0" * 16).freeze
FLAG_SAMPLED =
0x01
TRACESTATE_MAX_MEMBERS =

tracestate: lista di membri key=value separati da virgola, max 32 (W3C §3.3.1).

32
TRACESTATE_MEMBER =

key: lowercase alnum iniziale + set ristretto (incluso @// per le chiavi tenant@vendor). value: caratteri stampabili 0x20–0x7E esclusi , (0x2C) e = (0x3D).

%r{\A[a-z0-9][a-z0-9_\-*/@]*=[\x20-\x2b\x2d-\x3c\x3e-\x7e]+\z}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(trace_id:, parent_id:, flags:, tracestate: nil) ⇒ TraceContext

Returns a new instance of TraceContext.



38
39
40
41
42
43
# File 'lib/closeyourit/trace_context.rb', line 38

def initialize(trace_id:, parent_id:, flags:, tracestate: nil)
  @trace_id   = trace_id
  @parent_id  = parent_id
  @flags      = flags
  @tracestate = tracestate
end

Instance Attribute Details

#flagsObject (readonly)

Returns the value of attribute flags.



36
37
38
# File 'lib/closeyourit/trace_context.rb', line 36

def flags
  @flags
end

#parent_idObject (readonly)

Returns the value of attribute parent_id.



36
37
38
# File 'lib/closeyourit/trace_context.rb', line 36

def parent_id
  @parent_id
end

#trace_idObject (readonly)

Returns the value of attribute trace_id.



36
37
38
# File 'lib/closeyourit/trace_context.rb', line 36

def trace_id
  @trace_id
end

#tracestateObject (readonly)

Returns the value of attribute tracestate.



36
37
38
# File 'lib/closeyourit/trace_context.rb', line 36

def tracestate
  @tracestate
end

Class Method Details

.generate(sampled: true) ⇒ Object

Nuovo contesto root (nessun traceparent entrante valido). Genera trace-id (16 byte) e parent-id (8 byte) casuali — SecureRandom è fork-safe, così un worker forkato non riusa gli id del padre. sampled fissa il flag: un root che apriamo noi traccia di default.



68
69
70
71
72
73
74
75
# File 'lib/closeyourit/trace_context.rb', line 68

def generate(sampled: true)
  new(
    trace_id:   SecureRandom.hex(16),
    parent_id:  SecureRandom.hex(8),
    flags:      sampled ? FLAG_SAMPLED : 0,
    tracestate: nil
  )
end

.parse(traceparent, tracestate = nil) ⇒ Object

Adotta un traceparent entrante. Ritorna nil se malformato (→ il chiamante genera un root o lascia il contesto assente). Pass-through: mantiene trace-id/parent-id/flag verbatim così il bridge non inventa span. Il tracestate viene sanificato (membri invalidi scartati, cap a 32).



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/closeyourit/trace_context.rb', line 49

def parse(traceparent, tracestate = nil)
  match = TRACEPARENT.match(traceparent.to_s.strip)
  return nil unless match
  return nil if match[:version] == FORBIDDEN_VERSION
  return nil if match[:version] == CURRENT_VERSION && match[:rest]
  return nil if match[:trace_id] == ZERO_TRACE_ID
  return nil if match[:parent_id] == ZERO_PARENT_ID

  new(
    trace_id:   match[:trace_id],
    parent_id:  match[:parent_id],
    flags:      match[:flags].to_i(16),
    tracestate: sanitize_tracestate(tracestate)
  )
end

Instance Method Details

#headersObject

Header di propagazione W3C: traceparent (+ tracestate se presente). MAI baggage: può contenere contesto interno/PII e non deve varcare il confine (ticket: "baggage sensibile non riceve header").



103
104
105
106
107
# File 'lib/closeyourit/trace_context.rb', line 103

def headers
  result = { "traceparent" => traceparent }
  result["tracestate"] = tracestate if tracestate && !tracestate.empty?
  result
end

#sampled?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/closeyourit/trace_context.rb', line 91

def sampled?
  (flags & FLAG_SAMPLED) != 0
end

#traceparentObject

traceparent d'uscita, sempre versione 00 (l'unica che sappiamo emettere). I flag sono ri-emessi per intero (i bit riservati vanno propagati as-is), formattati su due cifre esadecimali.



97
98
99
# File 'lib/closeyourit/trace_context.rb', line 97

def traceparent
  format("%s-%s-%s-%02x", CURRENT_VERSION, trace_id, parent_id, flags & 0xff)
end