opencensus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rubocop.yml +48 -0
  4. data/.travis.yml +16 -0
  5. data/AUTHORS +1 -0
  6. data/CODE_OF_CONDUCT.md +43 -0
  7. data/CONTRIBUTING.md +34 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE +201 -0
  10. data/README.md +180 -0
  11. data/Rakefile +20 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/docs/.gitignore +3 -0
  15. data/docs/404.html +24 -0
  16. data/docs/Gemfile +31 -0
  17. data/docs/_config.yml +39 -0
  18. data/docs/_layouts/default.html +65 -0
  19. data/docs/index.md +151 -0
  20. data/lib/opencensus.rb +21 -0
  21. data/lib/opencensus/common.rb +24 -0
  22. data/lib/opencensus/common/config.rb +521 -0
  23. data/lib/opencensus/config.rb +54 -0
  24. data/lib/opencensus/context.rb +72 -0
  25. data/lib/opencensus/stats.rb +26 -0
  26. data/lib/opencensus/tags.rb +25 -0
  27. data/lib/opencensus/trace.rb +181 -0
  28. data/lib/opencensus/trace/annotation.rb +60 -0
  29. data/lib/opencensus/trace/config.rb +119 -0
  30. data/lib/opencensus/trace/exporters.rb +26 -0
  31. data/lib/opencensus/trace/exporters/logger.rb +149 -0
  32. data/lib/opencensus/trace/formatters.rb +29 -0
  33. data/lib/opencensus/trace/formatters/binary.rb +66 -0
  34. data/lib/opencensus/trace/formatters/cloud_trace.rb +102 -0
  35. data/lib/opencensus/trace/formatters/trace_context.rb +124 -0
  36. data/lib/opencensus/trace/integrations.rb +24 -0
  37. data/lib/opencensus/trace/integrations/faraday_middleware.rb +176 -0
  38. data/lib/opencensus/trace/integrations/rack_middleware.rb +127 -0
  39. data/lib/opencensus/trace/integrations/rails.rb +121 -0
  40. data/lib/opencensus/trace/link.rb +90 -0
  41. data/lib/opencensus/trace/message_event.rb +80 -0
  42. data/lib/opencensus/trace/samplers.rb +50 -0
  43. data/lib/opencensus/trace/samplers/always_sample.rb +34 -0
  44. data/lib/opencensus/trace/samplers/max_qps.rb +55 -0
  45. data/lib/opencensus/trace/samplers/never_sample.rb +34 -0
  46. data/lib/opencensus/trace/samplers/probability.rb +69 -0
  47. data/lib/opencensus/trace/span.rb +196 -0
  48. data/lib/opencensus/trace/span_builder.rb +560 -0
  49. data/lib/opencensus/trace/span_context.rb +308 -0
  50. data/lib/opencensus/trace/status.rb +49 -0
  51. data/lib/opencensus/trace/time_event.rb +38 -0
  52. data/lib/opencensus/trace/trace_context_data.rb +22 -0
  53. data/lib/opencensus/trace/truncatable_string.rb +61 -0
  54. data/lib/opencensus/version.rb +18 -0
  55. data/opencensus.gemspec +32 -0
  56. metadata +210 -0
@@ -0,0 +1,24 @@
1
+ # Copyright 2017 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module OpenCensus
16
+ module Trace
17
+ ##
18
+ # The Integrations module contains implementations of integrations with
19
+ # popular gems such as Rails and Faraday.
20
+ #
21
+ module Integrations
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,176 @@
1
+ # Copyright 2017 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "faraday"
16
+
17
+ module OpenCensus
18
+ module Trace
19
+ module Integrations
20
+ ##
21
+ # # Faraday integration
22
+ #
23
+ # This is a middleware for the Faraday HTTP client:
24
+ #
25
+ # * It wraps all outgoing requests in spans
26
+ # * It adds the trace context to outgoing requests.
27
+ #
28
+ # Example:
29
+ #
30
+ # conn = Faraday.new(url: "http://www.example.com") do |c|
31
+ # c.use OpenCensus::Trace::Integrations::FaradayMiddleware,
32
+ # span_name: "http request"
33
+ # c.adapter Faraday.default_adapter
34
+ # end
35
+ # conn.get "/"
36
+ #
37
+ # ## Configuring spans
38
+ #
39
+ # By default, spans are added to the thread-local span context, as if
40
+ # by calling `OpenCensus::Trace.start_span`. If there is no span context,
41
+ # then no span is added and this middleware effectively disables itself.
42
+ #
43
+ # You may also provide a span context, by passing it in the middleware
44
+ # options hash. For example:
45
+ #
46
+ # conn = Faraday.new(url: "http://www.example.com") do |c|
47
+ # c.use OpenCensus::Trace::Integrations::FaradayMiddleware,
48
+ # span_context: my_span_context
49
+ # c.adapter Faraday.default_adapter
50
+ # end
51
+ #
52
+ # You may also override the span context for a particular request by
53
+ # including it in the options:
54
+ #
55
+ # conn.get do |req|
56
+ # req.url "/"
57
+ # req.options.context = { span_context: my_span_context }
58
+ # end
59
+ #
60
+ # By default, all spans are given a default name. You may also override
61
+ # this by passing a `:span_name` in the middleware options hash and/or
62
+ # the request options.
63
+ #
64
+ # ## Trace context
65
+ #
66
+ # This currently adds a header to each outgoing request, propagating the
67
+ # trace context for distributed tracing. By default, this uses the
68
+ # formatter in the current config.
69
+ #
70
+ # You may provide your own implementation of the formatter by configuring
71
+ # it in the middleware options hash. For example:
72
+ #
73
+ # conn = Faraday.new(url: "http://www.example.com") do |c|
74
+ # c.use OpenCensus::Trace::Integrations::FaradayMiddleware,
75
+ # formatter: OpenCensus::Trace::Formatters::CloudTrace.new
76
+ # c.adapter Faraday.default_adapter
77
+ # end
78
+ #
79
+ # You many also override the formatter for a particular request by
80
+ # including it in the options:
81
+ #
82
+ # conn.get do |req|
83
+ # req.url "/"
84
+ # req.options.context = {
85
+ # formatter: OpenCensus::Trace::Formatters::CloudTrace.new
86
+ # }
87
+ # end
88
+ #
89
+ class FaradayMiddleware < Faraday::Middleware
90
+ ## The default name for Faraday spans
91
+ DEFAULT_SPAN_NAME = "faraday_request".freeze
92
+
93
+ ##
94
+ # Create a FaradayMiddleware.
95
+ #
96
+ # @param [#call] app Next item on the middleware stack.
97
+ # @param [SpanContext] span_context The span context within which
98
+ # to create spans. Optional: If omitted, spans are created in the
99
+ # current thread-local span context.
100
+ # @param [String, #call] span_name The name of the span to create.
101
+ # Can be a string or a callable that takes a faraday request env
102
+ # and returns a string. Optional: If omitted, uses
103
+ # `DEFAULT_SPAN_NAME`
104
+ # @param [#call] sampler The sampler to use when creating spans.
105
+ # Optional: If omitted, uses the sampler in the current config.
106
+ # @param [#serialize,#header_name] formatter The formatter to use when
107
+ # propagating span context. Optional: If omitted, use the formatter
108
+ # in the current config.
109
+ #
110
+ def initialize app, span_context: nil, span_name: nil, sampler: nil,
111
+ formatter: nil
112
+ @app = app
113
+ @span_context = span_context || OpenCensus::Trace
114
+ @span_name = span_name || DEFAULT_SPAN_NAME
115
+ @sampler = sampler
116
+ @formatter = formatter || OpenCensus::Trace.config.http_formatter
117
+ end
118
+
119
+ ##
120
+ # Wraps an HTTP call with a span with the request/response info.
121
+ # @private
122
+ #
123
+ def call request_env
124
+ span_context = request_env[:span_context] || @span_context
125
+ if span_context == OpenCensus::Trace && !span_context.span_context
126
+ return @app.call request_env
127
+ end
128
+
129
+ span_name = request_env[:span_name] || @span_name
130
+ span_name = span_name.call request_env if span_name.respond_to? :call
131
+
132
+ span = span_context.start_span span_name, sampler: @sampler
133
+ start_request span, request_env
134
+ @app.call(request_env).on_complete do |response_env|
135
+ finish_request span, response_env
136
+ span_context.end_span span
137
+ end
138
+ end
139
+
140
+ protected
141
+
142
+ ##
143
+ # @private Set span attributes from request object
144
+ #
145
+ def start_request span, env
146
+ req_method = env[:method]
147
+ span.put_attribute "/http/method", req_method if req_method
148
+ url = env[:url]
149
+ span.put_attribute "/http/url", url if url
150
+ body = env[:body]
151
+ body_size = body.bytesize if body.respond_to? :bytesize
152
+ span.put_attribute "/rpc/request/size", body_size if body_size
153
+
154
+ formatter = env[:formatter] || @formatter
155
+ trace_context = formatter.serialize span.context.trace_context
156
+ headers = env[:request_headers] ||= {}
157
+ headers[formatter.header_name] = trace_context
158
+ end
159
+
160
+ ##
161
+ # @private Set span attributes from response
162
+ #
163
+ def finish_request span, env
164
+ status = env[:status].to_i
165
+ if status > 0
166
+ span.set_status status
167
+ span.put_attribute "/rpc/status_code", status
168
+ end
169
+ body = env[:body]
170
+ body_size = body.bytesize if body.respond_to? :bytesize
171
+ span.put_attribute "/rpc/response/size", body_size if body_size
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,127 @@
1
+ # Copyright 2017 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module OpenCensus
16
+ module Trace
17
+ module Integrations
18
+ ##
19
+ # # Rack integration
20
+ #
21
+ # This is a middleware for Rack applications:
22
+ #
23
+ # * It wraps all incoming requests in a root span
24
+ # * It exports the captured spans at the end of the request.
25
+ #
26
+ # Example:
27
+ #
28
+ # require "opencensus/trace/integrations/rack_middleware"
29
+ #
30
+ # use OpenCensus::Trace::Integrations::RackMiddleware
31
+ #
32
+ class RackMiddleware
33
+ ##
34
+ # List of trace context formatters we use to parse the parent span
35
+ # context.
36
+ #
37
+ # @private
38
+ #
39
+ AUTODETECTABLE_FORMATTERS = [
40
+ Formatters::CloudTrace.new,
41
+ Formatters::TraceContext.new
42
+ ].freeze
43
+
44
+ ##
45
+ # Create the Rack middleware.
46
+ #
47
+ # @param [#call] app Next item on the middleware stack
48
+ # @param [#export] exporter The exported used to export captured spans
49
+ # at the end of the request. Optional: If omitted, uses the exporter
50
+ # in the current config.
51
+ #
52
+ def initialize app, exporter: nil
53
+ @app = app
54
+ @exporter = exporter || OpenCensus::Trace.config.exporter
55
+ end
56
+
57
+ ##
58
+ # Run the Rack middleware.
59
+ #
60
+ # @param [Hash] env The rack environment
61
+ # @return [Array] The rack response. An array with 3 elements: the HTTP
62
+ # response code, a Hash of the response headers, and the response
63
+ # body which must respond to `each`.
64
+ #
65
+ def call env
66
+ formatter = AUTODETECTABLE_FORMATTERS.detect do |f|
67
+ env.key? f.rack_header_name
68
+ end
69
+ if formatter
70
+ context = formatter.deserialize env[formatter.rack_header_name]
71
+ end
72
+
73
+ Trace.start_request_trace trace_context: context do |span_context|
74
+ begin
75
+ span_context.in_span get_path(env) do |span|
76
+ start_request span, env
77
+ @app.call(env).tap do |response|
78
+ finish_request span, response
79
+ end
80
+ end
81
+ ensure
82
+ @exporter.export span_context.build_contained_spans
83
+ end
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def get_path env
90
+ path = "#{env['SCRIPT_NAME']}#{env['PATH_INFO']}"
91
+ path = "/#{path}" unless path.start_with? "/"
92
+ path
93
+ end
94
+
95
+ def get_host env
96
+ env["HTTP_HOST"] || env["SERVER_NAME"]
97
+ end
98
+
99
+ def get_url env
100
+ path = get_path env
101
+ host = get_host env
102
+ scheme = env["SERVER_PROTOCOL"]
103
+ query_string = env["QUERY_STRING"].to_s
104
+ url = "#{scheme}://#{host}#{path}"
105
+ url = "#{url}?#{query_string}" unless query_string.empty?
106
+ url
107
+ end
108
+
109
+ def start_request span, env
110
+ span.put_attribute "/http/host", get_host(env)
111
+ span.put_attribute "/http/url", get_url(env)
112
+ span.put_attribute "/http/method", env["REQUEST_METHOD"]
113
+ span.put_attribute "/http/client_protocol", env["SERVER_PROTOCOL"]
114
+ span.put_attribute "/http/user_agent", env["HTTP_USER_AGENT"]
115
+ span.put_attribute "/pid", ::Process.pid.to_s
116
+ span.put_attribute "/tid", ::Thread.current.object_id.to_s
117
+ end
118
+
119
+ def finish_request span, response
120
+ if response.is_a?(::Array) && response.size == 3
121
+ span.set_status response[0]
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,121 @@
1
+ # Copyright 2017 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "active_support"
16
+ require "rails/railtie"
17
+ require "opencensus/trace/integrations/rack_middleware"
18
+
19
+ module OpenCensus
20
+ module Trace
21
+ module Integrations
22
+ ##
23
+ # # Rails Integration
24
+ #
25
+ # This Railtie automatically sets up OpenCensus for a Rails server:
26
+ #
27
+ # * It wraps all requests in spans, using the `RackMiddleware`
28
+ # integration.
29
+ # * It wraps common events (ActiveRecord database calls, ActionView
30
+ # renders, etc) in subspans.
31
+ #
32
+ # ## Configuration
33
+ #
34
+ # This Railtie exposes the OpenCensus configuration on the `opencensus`
35
+ # key of the Rails configuration. So you can, for example, set:
36
+ #
37
+ # config.opencensus.trace.default_max_attributes = 64
38
+ #
39
+ # This Railtie also provides a `notifications` configuration that
40
+ # supports the following fields:
41
+ #
42
+ # * `events` An array of strings indicating the events that will
43
+ # trigger the creation of spans. The default value is
44
+ # {OpenCensus::Trace::Integrations::Rails::DEFAULT_NOTIFICATION_EVENTS}.
45
+ # * `attribute_namespace` A string that will be prepended to all
46
+ # attributes copied from the event payload. Defaults to "`rails/`"
47
+ #
48
+ # You can access these in the `notifications` subconfiguration under
49
+ # the trace configuration. For example:
50
+ #
51
+ # OpenCensus::Trace.config do |config|
52
+ # config.notifications.attribute_namespace = "myapp/"
53
+ # end
54
+ #
55
+ # Or, using Rails:
56
+ #
57
+ # config.opencensus.trace.notifications.attribute_namespace = "myapp/"
58
+ #
59
+ class Rails < ::Rails::Railtie
60
+ ##
61
+ # The ActiveSupport notifications that will be reported as spans by
62
+ # default. To change this list, update the value of the
63
+ # `trace.notifications.events` configuration.
64
+ #
65
+ DEFAULT_NOTIFICATION_EVENTS = [
66
+ "sql.active_record",
67
+ "render_template.action_view",
68
+ "send_file.action_controller",
69
+ "send_data.action_controller",
70
+ "deliver.action_mailer"
71
+ ].freeze
72
+
73
+ OpenCensus::Trace.configure do |c|
74
+ c.add_config! :notifications do |rc|
75
+ rc.add_option! :events, DEFAULT_NOTIFICATION_EVENTS.dup
76
+ rc.add_option! :attribute_namespace, "rails/"
77
+ end
78
+ end
79
+
80
+ unless config.respond_to? :opencensus
81
+ config.opencensus = OpenCensus.configure
82
+ end
83
+
84
+ initializer "opencensus.trace" do |app|
85
+ app.middleware.insert_before ::Rack::Runtime, RackMiddleware
86
+ setup_notifications
87
+ end
88
+
89
+ ##
90
+ # Initialize notifications
91
+ # @private
92
+ #
93
+ def setup_notifications
94
+ OpenCensus::Trace.configure.notifications.events.each do |type|
95
+ ActiveSupport::Notifications.subscribe(type) do |*args|
96
+ event = ActiveSupport::Notifications::Event.new(*args)
97
+ handle_notification_event event
98
+ end
99
+ end
100
+ end
101
+
102
+ ##
103
+ # Add a span based on a notification event.
104
+ # @private
105
+ #
106
+ def handle_notification_event event
107
+ span_context = OpenCensus::Trace.span_context
108
+ if span_context
109
+ ns = OpenCensus::Trace.configure.notifications.attribute_namespace
110
+ span = span_context.start_span event.name, skip_frames: 2
111
+ span.start_time = event.time
112
+ span.end_time = event.end
113
+ event.payload.each do |k, v|
114
+ span.put_attribute "#{ns}#{k}", v.to_s
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end