rubyzipkin 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ # Tracing HTTP header types
2
+ module RubyZipkin
3
+ module ZipkinTraceHeader
4
+ TRACE_ID = "X-ZK-TID"
5
+ SPAN_ID = "X-ZK-SID"
6
+ PARENT_SPAN_ID = "X-ZK-PSID"
7
+ TRACE_SAMPLED = "X-ZK-SMP"
8
+ TRACE_FLAGS = "X-ZK-FLG"
9
+ FORCE_SAMPLE = "X-FORCE-SAMPLE"
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ require 'finagle-thrift'
2
+ require 'finagle-thrift/trace'
3
+
4
+
5
+ #writes properties and request headers as metadata into a trace
6
+ module RubyZipkin
7
+ class MetadataLogger
8
+
9
+ # log a key value pair into a zipkin trace as a KV span value
10
+ def self.log(key, value)
11
+ if key.to_s == "action_controller.rescue.request" || key.to_s == "action_controller.rescue.response"
12
+ ::Trace.record(::Trace::BinaryAnnotation.new(key, value.as_json.to_s, "STRING", ::Trace.default_endpoint))
13
+ else
14
+ ::Trace.record(::Trace::BinaryAnnotation.new(key, value.to_s, "STRING", ::Trace.default_endpoint))
15
+ end
16
+ end
17
+
18
+ # Do a full dump of a request header into zipkin.
19
+ def self.log_request(headers)
20
+ if headers
21
+ headers.each do |header, value|
22
+ MetadataLogger.log("HEADER_#{header}", value)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ require 'scribe'
2
+
3
+ # Scribe Writer
4
+ # Based on the original zipkin tracer game
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ module RubyZipkin
18
+ class Scriber
19
+ def initialize(scribe)
20
+ @scribe = scribe
21
+ end
22
+
23
+ def log(*args)
24
+ @scribe.log(*args)
25
+ rescue ThriftClient::NoServersAvailable, Thrift::Exception
26
+ end
27
+
28
+ def batch(&block)
29
+ @scribe.batch(&block)
30
+ rescue ThriftClient::NoServersAvailable, Thrift::Exception
31
+ end
32
+
33
+ def method_missing(name, *args)
34
+ @scribe.send(name, *args)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,35 @@
1
+ #Filters to decide wheter a request should be traced.
2
+ module RubyZipkin
3
+ class TraceFilter
4
+
5
+ # Filter uri's from being traced based on their type
6
+ # or a keyword listed in the blacklist
7
+ # Known static content requests like fonts are filtered as well
8
+ def self.UriFilterMatches?(uri, keyword_blacklist = [])
9
+ #exclude static content requests
10
+ if uri.to_s.match(/.*(\.svg)|(\.ttf)|(\.ott)|(\.woff)/)
11
+ return true
12
+ end
13
+
14
+ keyword_blacklist.each do |key|
15
+ if uri.to_s.match key
16
+ return true
17
+ end
18
+ end
19
+
20
+ return false
21
+ end
22
+
23
+ # Filter a string based on a keyword blacklist
24
+ # Meant to define if a key should be traced or not.
25
+ def self.KeywordFilterMatches?(keyword, keyword_blacklist = [])
26
+ #exclude static content requests
27
+ keyword_blacklist.each do |blacklisted|
28
+ if keyword.to_s.match(/.*(#{blacklisted}).*/)
29
+ return true
30
+ end
31
+ end
32
+ false
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ #Decides wheter a collected trace should be sampled or not.
2
+ module RubyZipkin
3
+ class TraceSampler
4
+
5
+ def self.request_sample_rate(request)
6
+
7
+ if request[RubyZipkin::ZipkinTraceHeader::FORCE_SAMPLE]
8
+ #filter is matched in the request, thus ensure not fitereed by returning 100% tracing (unsampled)
9
+ if request.body.matches(filter)
10
+ return 1
11
+ end
12
+ end
13
+ return 0.01
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module RubyZipkin
2
+ VERSION = "0.3.10"
3
+ end
data/lib/rubyzipkin.rb ADDED
@@ -0,0 +1,129 @@
1
+ require 'finagle-thrift'
2
+ require 'finagle-thrift/trace'
3
+ require 'scribe'
4
+
5
+ require 'rubyzipkin/version'
6
+ require 'rubyzipkin/scriber'
7
+ require 'rubyzipkin/headers'
8
+ require 'rubyzipkin/metadata_logger'
9
+ require 'rubyzipkin/tracesampler'
10
+ require 'rubyzipkin/trace_filter'
11
+
12
+
13
+ module RubyZipkin extend self
14
+
15
+ class RackHandler
16
+
17
+ def initialize(app, service_name, scribe_server, scribe_port, uri_filter_list = [], http_header_filter_list = [], scribe_max_buffer = 10, uri_sample_filter_list = {} , sampling_rate = 0.01)
18
+ @app = app
19
+ @lock = Mutex.new
20
+
21
+ puts "sampling rate = #{sampling_rate}"
22
+ puts "uri_sample_filter_list = #{uri_sample_filter_list}"
23
+
24
+ @service_name = service_name
25
+ @scribe_port = scribe_port
26
+ @sample_rate = sampling_rate
27
+ @uri_filter_list = uri_filter_list
28
+ @http_header_filter_list = http_header_filter_list
29
+ @scribe = Scribe.new("#{scribe_server}:#{scribe_port}")
30
+ ::Trace.tracer = ::Trace::ZipkinTracer.new(Scriber.new(@scribe), scribe_max_buffer)
31
+ end
32
+
33
+ def call(env)
34
+ begin
35
+ ::Trace.default_endpoint = ::Trace.default_endpoint.with_service_name(@service_name + "_#{normalized_uri(env['PATH_INFO'])}")
36
+ ::Trace.sample_rate = @sampling_rate
37
+ env[ZipkinTraceHeader::PARENT_SPAN_ID] = @spanid
38
+ env[ZipkinTraceHeader::TRACE_ID] = @tid
39
+ @status, @headers, @response = @app.call(env)
40
+ tracing_filter(get_or_create_trace_id2(env), env, @headers)
41
+ rescue => e
42
+ #Tracing errors shouldn't block a request.
43
+ puts "Zipkin error: #{e} \n #{e.backtrace}"
44
+ raise e
45
+ end
46
+ [@status, @headers, @response]
47
+ end
48
+
49
+ private
50
+ def tracing_filter(trace_id, env, headers=nil)
51
+ if RubyZipkin::TraceFilter.UriFilterMatches?(normalized_uri(env["PATH_INFO"]), @uri_filter_list)
52
+ return
53
+ end
54
+ @lock.synchronize do
55
+ ::Trace.push(trace_id)
56
+
57
+ set_trace_caption(env)
58
+ ::Trace.record(::Trace::BinaryAnnotation.new("http.uri", normalized_uri(env["PATH_INFO"]), "STRING", ::Trace.default_endpoint))
59
+ ::Trace.record(::Trace::BinaryAnnotation.new("http.status", @status.to_s, "STRING", ::Trace.default_endpoint))
60
+ ::Trace.record(::Trace::Annotation.new(::Trace::Annotation::SERVER_RECV, ::Trace.default_endpoint))
61
+
62
+ add_referer(env)
63
+ trace_hash(headers)
64
+ trace_hash(env)
65
+ trace_post_data(env["rack.input"].read)
66
+ end
67
+ yield if block_given?
68
+ ensure
69
+ @lock.synchronize do
70
+ ::Trace.record(::Trace::Annotation.new(::Trace::Annotation::SERVER_SEND, ::Trace.default_endpoint))
71
+ add_referer(env)
72
+ ::Trace.pop
73
+ end
74
+ end
75
+
76
+ def add_referer(env)
77
+ if env['HTTP_REFERER']
78
+ ::Trace.record(::Trace::BinaryAnnotation.new("http.referer", env['HTTP_REFERER'], "STRING", ::Trace.default_endpoint))
79
+ end
80
+ end
81
+
82
+ def normalized_uri(path)
83
+ path.gsub(/\/\d+/, '/:id')
84
+ end
85
+
86
+ def set_trace_caption(env)
87
+ ::Trace.set_rpc_name("#{env['REQUEST_METHOD']} - #{@status.to_s} - #{normalized_uri(env['PATH_INFO'])}")
88
+ end
89
+
90
+ def trace_post_data(content)
91
+ MetadataLogger.log('HTTP_REQUEST INPUT', content.to_s)
92
+ end
93
+
94
+ def trace_hash(content)
95
+ if content
96
+ content.sort.map do |k,v|
97
+ unless RubyZipkin::TraceFilter.KeywordFilterMatches?(k.to_s, @http_header_filter_list)
98
+ MetadataLogger.log(k.to_s, v)
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ def get_or_create_trace_id(env)
105
+ if env[ZipkinTraceHeader::TRACE_ID].nil? or env[ZipkinTraceHeader::TRACE_ID].to_s.empty?
106
+ @tid = Trace.generate_id
107
+ @parentspan = nil
108
+
109
+ env[ZipkinTraceHeader::TRACE_ID] = @tid
110
+ else
111
+ @tid = env[ZipkinTraceHeader::TRACE_ID]
112
+
113
+ if !env[ZipkinTraceHeader::SPAN_ID].nil? and !env[ZipkinTraceHeader::SPAN_ID].to_s.empty?
114
+ @parentspan = env[ZipkinTraceHeader::SPAN_ID]
115
+ end
116
+ end
117
+
118
+ @spanid = Trace.generate_id
119
+ env[ZipkinTraceHeader::SPAN_ID] = @spanid
120
+
121
+ # from Finagle source: flags are 0 = none , 1 = debug
122
+ Trace::TraceId.new @tid, @parentspan, @spanid, true, ::TRACE::Flags::DEBUG
123
+ end
124
+
125
+ def get_or_create_trace_id2(env)
126
+ ::Trace::TraceId.new(::Trace.generate_id, nil, ::Trace.generate_id, true, ::Trace::Flags::DEBUG)
127
+ end
128
+ end
129
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubyzipkin
3
+ version: !ruby/object:Gem::Version
4
+ hash: 7
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 10
10
+ version: 0.3.10
11
+ platform: ruby
12
+ authors:
13
+ - Ivan Marcin
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-11-05 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: scribe
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 31
29
+ segments:
30
+ - 0
31
+ - 2
32
+ - 4
33
+ version: 0.2.4
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: finagle-thrift
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 27
45
+ segments:
46
+ - 1
47
+ - 3
48
+ - 0
49
+ version: 1.3.0
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ description: Track rack header requests on zipkin
53
+ email:
54
+ - ivan.marcin@lookout.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - lib/rubyzipkin/headers.rb
63
+ - lib/rubyzipkin/metadata_logger.rb
64
+ - lib/rubyzipkin/scriber.rb
65
+ - lib/rubyzipkin/trace_filter.rb
66
+ - lib/rubyzipkin/tracesampler.rb
67
+ - lib/rubyzipkin/version.rb
68
+ - lib/rubyzipkin.rb
69
+ homepage: https://github.com/twitter/zipkin
70
+ licenses: []
71
+
72
+ post_install_message:
73
+ rdoc_options: []
74
+
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 17
92
+ segments:
93
+ - 1
94
+ - 3
95
+ - 5
96
+ version: 1.3.5
97
+ requirements: []
98
+
99
+ rubyforge_project:
100
+ rubygems_version: 1.8.25
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Ruby tracing via Zipkin
104
+ test_files: []
105
+