# frozen_string_literal: true# Released under the MIT License.# Copyright, 2021-2023, by Samuel Williams.require'securerandom'moduleTraces# A generic representation of the current tracing context.classContext# Parse a string representation of a distributed trace.# @parameter parent [String] The parent trace context.# @parameter state [Array(String)] Any attached trace state.defself.parse(parent,state=nil,**options)version,trace_id,parent_id,flags=parent.split('-')ifversion=='00'flags=Integer(flags,16)ifstate.is_a?(String)state=state.split(',')endifstatestate=state.map{|item|item.split('=')}.to_hendself.new(trace_id,parent_id,flags,state,**options)endend# Create a local trace context which is likley to be globally unique.# @parameter flags [Integer] Any trace context flags.defself.local(flags=0,**options)self.new(SecureRandom.hex(16),SecureRandom.hex(8),flags,**options)end# Nest a local trace context in an optional parent context.# @parameter parent [Context] An optional parent context.defself.nested(parent,flags=0)ifparentparent.nested(flags)elseself.local(flags)endendSAMPLED=0x01# Initialize the trace context.# @parameter trace_id [String] The ID of the whole trace forest.# @parameter parent_id [String] The ID of this operation as known by the caller (sometimes referred to as the span ID).# @parameter flags [Integer] An 8-bit field that controls tracing flags such as sampling, trace level, etc.# @parameter state [Hash] Additional vendor-specific trace identification information.# @parameter remote [Boolean] Whether this context was created from a distributed trace header.definitialize(trace_id,parent_id,flags,state=nil,remote: false)@trace_id=trace_id@parent_id=parent_id@flags=flags@state=state@remote=remoteend# Create a new nested trace context in which spans can be recorded.defnested(flags=@flags)Context.new(@trace_id,SecureRandom.hex(8),flags,@state,remote: @remote)end# The ID of the whole trace forest and is used to uniquely identify a distributed trace through a system. It is represented as a 16-byte array, for example, 4bf92f3577b34da6a3ce929d0e0e4736. All bytes as zero (00000000000000000000000000000000) is considered an invalid value.attr:trace_id# The ID of this operation as known by the caller (in some tracing systems, this is known as the span-id, where a span is the execution of a client operation). It is represented as an 8-byte array, for example, 00f067aa0ba902b7. All bytes as zero (0000000000000000) is considered an invalid value.attr:parent_id# An 8-bit field that controls tracing flags such as sampling, trace level, etc. These flags are recommendations given by the caller rather than strict rules.attr:flags# Provides additional vendor-specific trace identification information across different distributed tracing systems. Conveys information about the operation's position in multiple distributed tracing graphs.attr:state# Denotes that the caller may have recorded trace data. When unset, the caller did not record trace data out-of-band.defsampled?(@flags&SAMPLED)!=0end# Whether this context was created from a distributed trace header.defremote?@remoteend# A string representation of the trace context (excluding trace state).defto_s"00-#{@trace_id}-#{@parent_id}-#{@flags.to_s(16)}"end# Convert the trace context to a JSON representation, including trace state.defas_json{trace_id: @trace_id,parent_id: @parent_id,flags: @flags,state: @state,remote: @remote}end# Convert the trace context to a JSON string.defto_json(...)as_json.to_json(...)endendend