class Stackdriver::Core::TraceContext
A Stackdriver
trace context links the current request into a performance trace, and communicates tracing options between related requests. This functionality is used by the Stackdriver
diagnostics libraries (including google-cloud-trace, google-cloud-logging, and other rubygems) that integrate with the tracing service.
Most applications will not need to use the TraceContext
class directly. The Stackdriver
libraries use it internally to store and propagate context information.
Constants
- HEADER_RACK_KEY
@private
- MEMO_RACK_KEY
@private
- THREAD_KEY
@private
- UNCHANGED
@private
Attributes
The span ID, as a 64-bit integer, or `nil` if no span ID is present in the context.
@return [Integer, nil]
The trace ID, as a hex string.
@return [String]
Public Class Methods
Returns the current thread's trace context, or `nil` if no trace context has been set.
@return [TraceContext, nil]
@example
require "stackdriver/core" ctx = Stackdriver::Core::TraceContext.new Stackdriver::Core::TraceContext.set ctx same_ctx = Stackdriver::Core::TraceContext.get
# File lib/stackdriver/core/trace_context.rb, line 322 def self.get Thread.current[THREAD_KEY] end
Create a new TraceContext
instance.
@param [String] trace_id
The trace ID as a hex string. If nil or
omitted, a new random Trace ID will be generated, and this TraceContext will be marked as new.
@param [Boolean] is_new Whether this trace context should be flagged
as newly created. Optional: if unset, will reflect whether a new trace_id was generated when this object was created.
@param [Integer] span_id
The context parent span ID as a 64-bit int.
If nil or omitted, the context will specify no parent span.
@param [Boolean] sampled Whether the context has decided to sample
this trace or not, or nil if the context does not specify a sampling decision.
@param [Boolean] capture_stack Whether the the context has decided to
capture stack traces. Ignored if sampled is not true.
@example
require "stackdriver/core" trace_id = "0123456789abcdef0123456789abcdef" ctx = Stackdriver::Core::TraceContext.new trace_id: trace_id, sampled: true
# File lib/stackdriver/core/trace_context.rb, line 70 def initialize trace_id: nil, is_new: nil, span_id: nil, sampled: nil, capture_stack: false @trace_id = trace_id || new_random_trace_id @is_new = if is_new.nil? !trace_id else is_new ? true : false end @span_id = span_id ? span_id.to_i : nil @sampled = sampled if @sampled.nil? @capture_stack = nil else @sampled = @sampled ? true : false @capture_stack = capture_stack && @sampled end end
Obtains a TraceContext
from the given Rack environment. This should be used by any service that wants to obtain the TraceContext
for a Rack request. If a new trace context is generated in the process, it is memoized into the Rack environment so subsequent services will get the same context.
Specifically, the following steps are attempted in order:
1. Attempts to use any memoized context previously obtained. 2. Attempts to parse the trace context header. 3. Creates a new trace context with a random trace ID.
Furthermore, if a block is given, it is provided with an opportunity to modify the trace context. The current trace context and the Rack environment is passed to the block, and its result is used as the final trace context. The final context is memoized back into the Rack environment.
@param [Hash] env The Rack environment hash
@return [TraceContext]
@example
require "stackdriver/core" class MyMiddleware def initialize app @app = app end def call env ctx = Stackdriver::Core::TraceContext.parse_rack_env env do_something_with ctx @app.call env end end
# File lib/stackdriver/core/trace_context.rb, line 281 def self.parse_rack_env env trace_context = env[MEMO_RACK_KEY] || parse_string(env[HEADER_RACK_KEY].to_s) || new trace_context = yield trace_context, env if block_given? env[MEMO_RACK_KEY] = trace_context end
Attempts to parse the given string as a trace context representation. Expects the form `<require "stackdriver/core"
str = "0123456789abcdef0123456789abcdef/12345;o=1"
ctx = Stackdriver::Core::TraceContext.parse_string str
# File lib/stackdriver/core/trace_context.rb, line 227
def self.parse_string str
match = %r|^(\w{32})(/(\d+))?(;o=(\d+))?|.match str
return unless match
trace_id = match[1]
span_id = match[3] ? match[3].to_i : nil
options = match[5] ? match[5].to_i : nil
if options.nil?
sampled = capture_stack = nil
else
sampled = options & 1 != 0
capture_stack = options & 2 != 0
end
new trace_id: trace_id, span_id: span_id, sampled: sampled,
capture_stack: capture_stack
end
Set the current thread's trace context, and returns the context.
@param [TraceContext, nil] trace_context The trace context to
set for the current thread. May be `nil`.
@return [TraceContext, nil] The context set.
@example
require "stackdriver/core" ctx = Stackdriver::Core::TraceContext.new Stackdriver::Core::TraceContext.set ctx same_ctx = Stackdriver::Core::TraceContext.get
# File lib/stackdriver/core/trace_context.rb, line 304 def self.set trace_context Thread.current[THREAD_KEY] = trace_context trace_context end
Public Instance Methods
Returns `true` if the context wants to capture stack traces, `false` if the context does not, or `nil` if the context does not specify a sampling decision.
@return [Boolean, nil]
# File lib/stackdriver/core/trace_context.rb, line 121 def capture_stack? @capture_stack end
Standard value equality check for this object.
@param [Object] other An object to compare with. @return [Boolean]
# File lib/stackdriver/core/trace_context.rb, line 140 def eql? other other.is_a?(TraceContext) && trace_id == other.trace_id && new? == other.new? && span_id == other.span_id && sampled? == other.sampled? && capture_stack? == other.capture_stack? end
Generate standard hash code for this object.
@return [Integer]
# File lib/stackdriver/core/trace_context.rb, line 155 def hash @hash ||= @trace_id.hash ^ @is_new.hash ^ @span_id.hash ^ @sampled.hash ^ @capture_stack.hash end
Returns `true` if this trace includes a newly generated trace_id.
@return [Boolean]
# File lib/stackdriver/core/trace_context.rb, line 130 def new? @is_new end
Returns `true` if the context wants to sample, `false` if the context wants explicitly to disable sampling, or `nil` if the context does not specify.
@return [Boolean, nil]
# File lib/stackdriver/core/trace_context.rb, line 110 def sampled? @sampled end
Returns a string representation of this trace context, in the form `<
# File lib/stackdriver/core/trace_context.rb, line 198
def to_string
str = trace_id
str += "/#{span_id}" if span_id
unless sampled?.nil?
options = 0
options |= 1 if sampled?
options |= 2 if capture_stack?
str += ";o=#{options}"
end
str
end
Returns a new TraceContext
instance that is identical to this instance except for the given changes. All parameters are optional. See {TraceContext#initialize} for more details on each parameter.
@param [String] trace_id
New trace ID. @param [Boolean] is_new New setting for newness indicator. @param [Integer] span_id
New parent span ID. @param [Boolean] sampled New sampling decision. @param [Boolean] capture_stack New stack capture decision. @return [TraceContext]
@example
require "stackdriver/core" trace_id = "0123456789abcdef0123456789abcdef" orig_ctx = Stackdriver::Core::TraceContext.new trace_id: trace_id, sampled_ctx = orig_ctx.with sampled: true
# File lib/stackdriver/core/trace_context.rb, line 180 def with trace_id: UNCHANGED, is_new: UNCHANGED, span_id: UNCHANGED, sampled: UNCHANGED, capture_stack: UNCHANGED trace_id = @trace_id if trace_id == UNCHANGED is_new = @is_new if is_new == UNCHANGED span_id = @span_id if span_id == UNCHANGED sampled = @sampled if sampled == UNCHANGED capture_stack = @capture_stack if capture_stack == UNCHANGED TraceContext.new trace_id: trace_id, is_new: is_new, span_id: span_id, sampled: sampled, capture_stack: capture_stack end
Protected Instance Methods
Returns a random trace ID (as a random type 4 UUID).
@private @return [String]
# File lib/stackdriver/core/trace_context.rb, line 334 def new_random_trace_id val = rand 0x100000000000000000000000000000000 val &= 0xffffffffffff0fffcfffffffffffffff val |= 0x00000000000040008000000000000000 format "%032x", val end