Permalink
Browse files

[split] Add flags field to thrift header in finagle-thrift Ruby gem. …

…Finagle has added a flags field in the headers. This is currently only used to pass through a debug flag. If set, that flag ensures that the Zipkin back end will skip sampling and store that trace. This is useful for developers who can then make sure the trace for a particular request is stored.

RB_ID=78254
  • Loading branch information...
1 parent 048d153 commit 47a078593e6d4ea1dbe98d74681ed0c106991b33 Johan Oskarsson committed Aug 2, 2012
@@ -21,7 +21,7 @@ def send_message(name, args_class, args = {})
header.parent_span_id = Trace.id.parent_id.to_i
header.span_id = Trace.id.span_id.to_i
header.sampled = Trace.id.sampled?
- header.debug = false
+ header.flags = Trace.id.flags.to_i
header.client_id = client_id if client_id
@@ -43,11 +43,13 @@ class Annotation
TIMESTAMP = 1
VALUE = 2
HOST = 3
+ DURATION = 4
FIELDS = {
TIMESTAMP => {:type => ::Thrift::Types::I64, :name => 'timestamp'},
VALUE => {:type => ::Thrift::Types::STRING, :name => 'value'},
- HOST => {:type => ::Thrift::Types::STRUCT, :name => 'host', :class => FinagleThrift::Endpoint, :optional => true}
+ HOST => {:type => ::Thrift::Types::STRUCT, :name => 'host', :class => FinagleThrift::Endpoint, :optional => true},
+ DURATION => {:type => ::Thrift::Types::I32, :name => 'duration', :optional => true}
}
def struct_fields; FIELDS; end
@@ -91,14 +93,16 @@ class Span
PARENT_ID = 5
ANNOTATIONS = 6
BINARY_ANNOTATIONS = 8
+ DEBUG = 9
FIELDS = {
TRACE_ID => {:type => ::Thrift::Types::I64, :name => 'trace_id'},
NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
ID => {:type => ::Thrift::Types::I64, :name => 'id'},
PARENT_ID => {:type => ::Thrift::Types::I64, :name => 'parent_id', :optional => true},
ANNOTATIONS => {:type => ::Thrift::Types::LIST, :name => 'annotations', :element => {:type => ::Thrift::Types::STRUCT, :class => FinagleThrift::Annotation}},
- BINARY_ANNOTATIONS => {:type => ::Thrift::Types::LIST, :name => 'binary_annotations', :element => {:type => ::Thrift::Types::STRUCT, :class => FinagleThrift::BinaryAnnotation}}
+ BINARY_ANNOTATIONS => {:type => ::Thrift::Types::LIST, :name => 'binary_annotations', :element => {:type => ::Thrift::Types::STRUCT, :class => FinagleThrift::BinaryAnnotation}},
+ DEBUG => {:type => ::Thrift::Types::BOOL, :name => 'debug'}
}
def struct_fields; FIELDS; end
@@ -134,17 +138,17 @@ class RequestHeader
TRACE_ID = 1
SPAN_ID = 2
PARENT_SPAN_ID = 3
- DEBUG = 4
SAMPLED = 5
CLIENT_ID = 6
+ FLAGS = 7
FIELDS = {
TRACE_ID => {:type => ::Thrift::Types::I64, :name => 'trace_id'},
SPAN_ID => {:type => ::Thrift::Types::I64, :name => 'span_id'},
PARENT_SPAN_ID => {:type => ::Thrift::Types::I64, :name => 'parent_span_id', :optional => true},
- DEBUG => {:type => ::Thrift::Types::BOOL, :name => 'debug'},
SAMPLED => {:type => ::Thrift::Types::BOOL, :name => 'sampled', :optional => true},
- CLIENT_ID => {:type => ::Thrift::Types::STRUCT, :name => 'client_id', :class => FinagleThrift::ClientId, :optional => true}
+ CLIENT_ID => {:type => ::Thrift::Types::STRUCT, :name => 'client_id', :class => FinagleThrift::ClientId, :optional => true},
+ FLAGS => {:type => ::Thrift::Types::I64, :name => 'flags', :optional => true}
}
def struct_fields; FIELDS; end
@@ -6,7 +6,7 @@ module Trace
def id
if stack.empty?
span_id = generate_id
- trace_id = TraceId.new(span_id, nil, span_id, should_sample?)
+ trace_id = TraceId.new(span_id, nil, span_id, should_sample?, Flags::EMPTY)
stack.push(trace_id)
end
stack.last
@@ -58,23 +58,45 @@ def tracer=(tracer)
end
class TraceId
- attr_reader :trace_id, :parent_id, :span_id, :sampled
- alias :sampled? :sampled
- def initialize(trace_id, parent_id, span_id, sampled)
+ attr_reader :trace_id, :parent_id, :span_id, :sampled, :flags
+
+ def initialize(trace_id, parent_id, span_id, sampled, flags)
@trace_id = SpanId.from_value(trace_id)
@parent_id = parent_id.nil? ? nil : SpanId.from_value(parent_id)
@span_id = SpanId.from_value(span_id)
@sampled = !!sampled
+ @flags = flags
end
def next_id
- TraceId.new(@trace_id, @span_id, Trace.generate_id, @sampled)
+ TraceId.new(@trace_id, @span_id, Trace.generate_id, @sampled, @flags)
+ end
+
+ # the debug flag is used to ensure the trace passes ALL samplers
+ def debug?
+ @flags & Flags::DEBUG == Flags::DEBUG
+ end
+
+ def sampled?
+ debug? || @sampled
end
def to_s
- "TraceId(trace_id = #{@trace_id.to_s}, parent_id = #{@parent_id.to_s}, span_id = #{@span_id.to_s}, sampled = #{@sampled.to_s})"
+ "TraceId(trace_id = #{@trace_id.to_s}, parent_id = #{@parent_id.to_s}, span_id = #{@span_id.to_s}, sampled = #{@sampled.to_s}, flags = #{@flags.to_s})"
end
end
+
+ # there are a total of 64 flags that can be passed down with the various tracing headers
+ # at the time of writing only one is used (debug).
+ #
+ # Note that using the 64th bit in Ruby requires some sign conversion since Thrift i64s are signed
+ # but Ruby won't do the right thing if you try to set 1 << 64
+ class Flags
+ # no flags set
+ EMPTY = 0
+ # the debug flag is used to ensure we pass all the sampling layers and that the trace is stored
+ DEBUG = 1
+ end
class SpanId
HEX_REGEX = /^[a-f0-9]{16}$/i
@@ -121,12 +121,13 @@ def flush!
end
class Span
- attr_accessor :name, :annotations, :binary_annotations
+ attr_accessor :name, :annotations, :binary_annotations, :debug
def initialize(name, span_id)
@name = name
@span_id = span_id
@annotations = []
@binary_annotations = []
+ @debug = span_id.debug?
end
def to_thrift
@@ -136,7 +137,8 @@ def to_thrift
:id => @span_id.span_id.to_i,
:parent_id => @span_id.parent_id.nil? ? nil : @span_id.parent_id.to_i,
:annotations => @annotations.map { |a| a.to_thrift },
- :binary_annotations => @binary_annotations.map { |a| a.to_thrift }
+ :binary_annotations => @binary_annotations.map { |a| a.to_thrift },
+ :debug => @debug
)
end
end
@@ -147,7 +149,8 @@ class Annotation
SERVER_SEND = "ss"
SERVER_RECV = "sr"
- attr_reader :value, :host, :timestamp
+ # write access for tests
+ attr_accessor :value, :host, :timestamp
def initialize(value, host)
@timestamp = (Time.now.to_f * 1000 * 1000).to_i # micros
@value = value
@@ -1,3 +1,3 @@
module FinagleThrift
- VERSION = "1.2.0"
+ VERSION = "1.3.0"
end
@@ -0,0 +1,25 @@
+require 'rubygems'
+require 'thrift'
+require 'finagle-thrift'
+require 'test/unit'
+
+class TraceIdTest < Test::Unit::TestCase
+ def test_debug_flag
+ id = Trace::TraceId.new(0, 1, 2, false, Trace::Flags::DEBUG)
+ assert_equal true, id.debug?
+ assert_equal true, id.next_id.debug?
+ # the passed in sampled is overriden if debug is true
+ assert_equal true, id.sampled?
+ assert_equal true, id.next_id.sampled?
+
+ id = Trace::TraceId.new(0, 1, 2, false, Trace::Flags::EMPTY)
+ assert_equal false, id.debug?
+ assert_equal false, id.next_id.debug?
+ end
+
+ def test_span_id
+ id = Trace::SpanId.new(Trace.generate_id)
+ id2 = Trace::SpanId.from_value(id.to_s)
+ assert_equal id.to_i, id2.to_i
+ end
+end
@@ -0,0 +1,44 @@
+require 'rubygems'
+require 'thrift'
+require 'finagle-thrift'
+require 'test/unit'
+require 'base64'
+
+class ScribeMock
+ attr_accessor :message
+ def log(message, category)
+ @message = message
+ end
+
+ def batch
+ yield
+ end
+end
+
+class TracerTest < Test::Unit::TestCase
+ def test_serialize_debug_true
+ id = Trace::TraceId.new(0, 1, 2, true, Trace::Flags::DEBUG)
+ annotation = Trace::Annotation.new(Trace::Annotation::SERVER_SEND, Trace::Endpoint.new(0, 0, "service"))
+ annotation.timestamp = 123
+
+ scribe = ScribeMock.new
+ tracer = Trace::ZipkinTracer.new(scribe, 10)
+ tracer.set_rpc_name(id, "name")
+ tracer.record(id, annotation)
+ assert_equal "CgABAAAAAAAAAAALAAMAAAAEbmFtZQoABAAAAAAAAAACCgAFAAAAAAAAAAEPAAYMAAAAAQoAAQAAAAAA" +
+ "AAB7CwACAAAAAnNzDAADCAABAAAAAAYAAgAACwADAAAAB3NlcnZpY2UAAA8ACAwAAAAAAgAJAQA=", scribe.message
+ end
+
+ def test_serialize_debug_false
+ id = Trace::TraceId.new(0, 1, 2, true, Trace::Flags::EMPTY)
+ annotation = Trace::Annotation.new(Trace::Annotation::SERVER_SEND, Trace::Endpoint.new(0, 0, "service"))
+ annotation.timestamp = 123
+
+ scribe = ScribeMock.new
+ tracer = Trace::ZipkinTracer.new(scribe, 10)
+ tracer.set_rpc_name(id, "name")
+ tracer.record(id, annotation)
+ assert_equal "CgABAAAAAAAAAAALAAMAAAAEbmFtZQoABAAAAAAAAAACCgAFAAAAAAAAAAEPAAYMAAAAAQoAAQAAAAAA" +
+ "AAB7CwACAAAAAnNzDAADCAABAAAAAAYAAgAACwADAAAAB3NlcnZpY2UAAA8ACAwAAAAAAgAJAAA=", scribe.message
+ end
+end

0 comments on commit 47a0785

Please sign in to comment.