25thread_local trace_context tls_current_context;
28constexpr std::array<char, 16> hex_chars = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
29 '8',
'9',
'a',
'b',
'c',
'd',
'e',
'f'};
32auto hex_char_to_value(
char c) ->
int
34 if (c >=
'0' && c <=
'9')
38 if (c >=
'a' && c <=
'f')
42 if (c >=
'A' && c <=
'F')
50auto is_zero_trace_id(
const trace_id_t&
id) ->
bool
52 return std::all_of(
id.begin(),
id.end(), [](uint8_t b) {
return b == 0; });
56auto is_zero_span_id(
const span_id_t&
id) ->
bool
58 return std::all_of(
id.begin(),
id.end(), [](uint8_t b) {
return b == 0; });
62auto get_random_bytes(uint8_t* buffer,
size_t size) ->
void
64 static thread_local std::random_device rd;
65 static thread_local std::mt19937_64 gen(rd());
66 static thread_local std::uniform_int_distribution<uint64_t> dist;
71 uint64_t value = dist(gen);
72 size_t to_copy = std::min(
sizeof(value), size - offset);
73 std::memcpy(buffer + offset, &value, to_copy);
81 std::optional<span_id_t> parent_span_id)
84 , parent_span_id_(std::move(parent_span_id))
86 , valid_(!is_zero_trace_id(
trace_id) && !is_zero_span_id(span_id))
92 return tls_current_context;
97 tls_current_context = ctx;
108 if (tls_current_context.is_valid())
110 return tls_current_context.create_child_span(name);
118 return span(name, new_ctx);
130 return span(name, new_ctx);
135 trace_context child_ctx(trace_id_, new_span_id, flags_, span_id_);
137 return span(name, child_ctx);
149 std::ostringstream oss;
161 -> std::vector<std::pair<std::
string, std::
string>>
163 std::vector<std::pair<std::string, std::string>> headers;
176 if (traceparent.size() < 55)
182 if (traceparent[0] !=
'0' || traceparent[1] !=
'0' || traceparent[2] !=
'-')
195 if (traceparent[35] !=
'-')
202 if (!
hex_to_bytes(traceparent.substr(36, 16), span_id.data(), 8))
208 if (traceparent[52] !=
'-')
214 int high = hex_char_to_value(traceparent[53]);
215 int low = hex_char_to_value(traceparent[54]);
216 if (high < 0 || low < 0)
221 auto flags =
static_cast<trace_flags>((high << 4) | low);
227 const std::vector<std::pair<std::string, std::string>>& headers) ->
trace_context
229 for (
const auto& [name, value] : headers)
232 std::string lower_name = name;
233 std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
234 [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
236 if (lower_name ==
"traceparent")
238 auto ctx = from_traceparent(value);
291 return trace_id_ == other.trace_id_ && span_id_ == other.span_id_ &&
292 parent_span_id_ == other.parent_span_id_ && flags_ == other.flags_ &&
293 valid_ == other.valid_;
298 return !(*
this == other);
304 get_random_bytes(
id.data(),
id.size());
311 get_random_bytes(
id.data(),
id.size());
318 result.reserve(size * 2);
320 for (
size_t i = 0; i < size; ++i)
322 result.push_back(hex_chars[(data[i] >> 4) & 0x0F]);
323 result.push_back(hex_chars[data[i] & 0x0F]);
329auto hex_to_bytes(std::string_view hex, uint8_t* out,
size_t size) ->
bool
331 if (hex.size() != size * 2)
336 for (
size_t i = 0; i < size; ++i)
338 int high = hex_char_to_value(hex[i * 2]);
339 int low = hex_char_to_value(hex[i * 2 + 1]);
341 if (high < 0 || low < 0)
346 out[i] =
static_cast<uint8_t
>((high << 4) | low);
RAII span for distributed tracing.
Immutable trace context for distributed tracing.
static auto create_span(std::string_view name) -> span
Create a new root span with a new trace context.
auto trace_id() const noexcept -> const trace_id_t &
Get the trace ID.
auto span_id_hex() const -> std::string
Convert span ID to hex string.
static auto current() -> trace_context
Get the current trace context from thread-local storage.
static void clear_current()
Clear the current thread-local trace context.
auto trace_id_hex() const -> std::string
Convert trace ID to hex string.
static auto from_headers(const std::vector< std::pair< std::string, std::string > > &headers) -> trace_context
Parse trace context from HTTP headers.
auto to_headers() const -> std::vector< std::pair< std::string, std::string > >
Convert context to HTTP headers for propagation.
static auto from_traceparent(std::string_view traceparent) -> trace_context
Parse trace context from W3C traceparent header.
auto parent_span_id() const noexcept -> const std::optional< span_id_t > &
Get the parent span ID.
auto is_sampled() const noexcept -> bool
Check if this trace is sampled.
auto flags() const noexcept -> trace_flags
Get the trace flags.
auto operator==(const trace_context &other) const noexcept -> bool
Equality comparison.
auto create_child_span(std::string_view name) const -> span
Create a child span inheriting this context.
auto is_valid() const noexcept -> bool
Check if this context is valid.
std::optional< span_id_t > parent_span_id_
static void set_current(const trace_context &ctx)
Set the current thread-local trace context.
auto span_id() const noexcept -> const span_id_t &
Get the span ID.
trace_context()=default
Default constructor creates an invalid context.
auto operator!=(const trace_context &other) const noexcept -> bool
Inequality comparison.
auto to_traceparent() const -> std::string
Convert context to W3C traceparent header value.
auto bytes_to_hex(const uint8_t *data, size_t size) -> std::string
Convert bytes to lowercase hex string.
trace_flags
Trace flags (8-bit)
auto generate_span_id() -> span_id_t
Generate a random span ID.
std::array< uint8_t, 8 > span_id_t
Span ID type (64-bit identifier)
auto generate_trace_id() -> trace_id_t
Generate a random trace ID.
auto hex_to_bytes(std::string_view hex, uint8_t *out, size_t size) -> bool
Parse hex string to bytes.
@ trace_id
Sample based on trace ID ratio.
std::array< uint8_t, 16 > trace_id_t
Trace ID type (128-bit identifier)
RAII span implementation for distributed tracing.
Distributed tracing context for OpenTelemetry-compatible tracing.