d13n 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.rspec +6 -0
- data/.rubocop.yml +5 -0
- data/.ruby-version +1 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +151 -0
- data/Guardfile +63 -0
- data/README.md +200 -0
- data/bin/d13n +11 -0
- data/d13n.gemspec +34 -0
- data/lib/d13n/application/class_methods.rb +56 -0
- data/lib/d13n/application.rb +3 -0
- data/lib/d13n/cli/command.rb +76 -0
- data/lib/d13n/cli/commands/scaffold.rb +345 -0
- data/lib/d13n/configuration/default_source.rb +200 -0
- data/lib/d13n/configuration/dotted_hash.rb +39 -0
- data/lib/d13n/configuration/environment_source.rb +89 -0
- data/lib/d13n/configuration/manager.rb +239 -0
- data/lib/d13n/configuration/manual_source.rb +4 -0
- data/lib/d13n/configuration/mask_defaults.rb +6 -0
- data/lib/d13n/configuration/server_source.rb +83 -0
- data/lib/d13n/configuration/yaml_source.rb +66 -0
- data/lib/d13n/configuration.rb +6 -0
- data/lib/d13n/ext/string.rb +17 -0
- data/lib/d13n/logger/log_once.rb +24 -0
- data/lib/d13n/logger/memory_logger.rb +48 -0
- data/lib/d13n/logger/null_logger.rb +16 -0
- data/lib/d13n/logger.rb +213 -0
- data/lib/d13n/metric/conductor.rb +123 -0
- data/lib/d13n/metric/helper.rb +62 -0
- data/lib/d13n/metric/http_clients/http_helper.rb +15 -0
- data/lib/d13n/metric/http_clients/net_http_wrappers.rb +54 -0
- data/lib/d13n/metric/http_clients.rb +4 -0
- data/lib/d13n/metric/instrumentation/app_exception.rb +70 -0
- data/lib/d13n/metric/instrumentation/controller_instrumentation.rb +91 -0
- data/lib/d13n/metric/instrumentation/em-websocket.rb +71 -0
- data/lib/d13n/metric/instrumentation/exception.rb +65 -0
- data/lib/d13n/metric/instrumentation/middleware_tracing.rb +82 -0
- data/lib/d13n/metric/instrumentation/net.rb +36 -0
- data/lib/d13n/metric/instrumentation/sinatra/stream_namer.rb +35 -0
- data/lib/d13n/metric/instrumentation/sinatra.rb +165 -0
- data/lib/d13n/metric/instrumentation/websocket_instrumentation.rb +42 -0
- data/lib/d13n/metric/instrumentation.rb +41 -0
- data/lib/d13n/metric/manager.rb +106 -0
- data/lib/d13n/metric/metrics/app_database_metric.rb +4 -0
- data/lib/d13n/metric/metrics/app_http_metric.rb +229 -0
- data/lib/d13n/metric/metrics/app_state_metric.rb +103 -0
- data/lib/d13n/metric/metrics/base.rb +14 -0
- data/lib/d13n/metric/metrics/biz_state_metric.rb +4 -0
- data/lib/d13n/metric/metrics.rb +6 -0
- data/lib/d13n/metric/stream/span_tracer_helpers.rb +72 -0
- data/lib/d13n/metric/stream/stream_tracer_helpers.rb +141 -0
- data/lib/d13n/metric/stream/traced_span_stack.rb +73 -0
- data/lib/d13n/metric/stream.rb +322 -0
- data/lib/d13n/metric/stream_state.rb +68 -0
- data/lib/d13n/metric.rb +11 -0
- data/lib/d13n/rack/d13n_middleware.rb +21 -0
- data/lib/d13n/rack/metric_middleware.rb +18 -0
- data/lib/d13n/service/background_job/sinatra.rb +24 -0
- data/lib/d13n/service/background_job.rb +1 -0
- data/lib/d13n/service/start.rb +75 -0
- data/lib/d13n/service.rb +91 -0
- data/lib/d13n/support/request_id.rb +29 -0
- data/lib/d13n/version.rb +14 -0
- data/lib/d13n.rb +92 -0
- data/templates/.rspec.template +6 -0
- data/templates/.ruby-version.template +1 -0
- data/templates/Gemfile.template +16 -0
- data/templates/Guardfile.template +64 -0
- data/templates/Jenkinsfile.template +85 -0
- data/templates/Makefile.template +178 -0
- data/templates/README.md.template +1 -0
- data/templates/Rakefile.template +6 -0
- data/templates/application.yml.template +14 -0
- data/templates/config.ru.template +4 -0
- data/templates/docker/.dockerignore.template +5 -0
- data/templates/docker/Dockerfile.application.development +15 -0
- data/templates/docker/Dockerfile.cache.development +18 -0
- data/templates/docker/Dockerfile.development +27 -0
- data/templates/docker/Dockerfile.release +16 -0
- data/templates/docker/docker-compose.yml.development +53 -0
- data/templates/docker/docker-compose.yml.release +37 -0
- data/templates/lib/api/service.rb.template +10 -0
- data/templates/lib/api/support.rb.template +38 -0
- data/templates/lib/api/version.rb.template +3 -0
- data/templates/lib/api.rb.template +4 -0
- data/templates/lib/application.rb.template +49 -0
- data/templates/lib/service.rb.template +4 -0
- data/templates/lib/version.rb.template +3 -0
- data/templates/scripts/test.sh.template +7 -0
- data/templates/spec/spec_helper.rb.template +56 -0
- data/templates/tasks/migration.rake.template +11 -0
- data/templates/tasks/spec.rake.template +21 -0
- metadata +199 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module D13n::Metric::Instrumentation
|
2
|
+
module Exception
|
3
|
+
def self.included(descendance)
|
4
|
+
descendance.include(InstanceMethods)
|
5
|
+
descendance.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
module ClassMethods
|
8
|
+
def d13n_error_inherated?
|
9
|
+
!!(self < D13n::Error)
|
10
|
+
end
|
11
|
+
|
12
|
+
def exception_with_d13n_instrumentation(*arg)
|
13
|
+
return exception_without_d13n_instrumentation(*arg) if d13n_error_inherated?
|
14
|
+
|
15
|
+
manager = D13n::Metric::Manager.instance
|
16
|
+
metric = manager.metric(:app_state)
|
17
|
+
|
18
|
+
if metric.nil?
|
19
|
+
D13n.logger.info "Null intrumentation metric class and ignore collection"
|
20
|
+
return exception_without_d13n_instrumentation(*arg)
|
21
|
+
end
|
22
|
+
|
23
|
+
metric.instance(manager, {type: 'exception', at: 'runtime', src:'others'}).process do
|
24
|
+
exception_without_d13n_instrumentation(*arg)
|
25
|
+
end
|
26
|
+
return exception_without_d13n_instrumentation(*arg)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module InstanceMethods
|
31
|
+
def exception_with_d13n_instrumentation(*arg)
|
32
|
+
self.class.exception_with_d13n_instrumentation(*arg)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module_function
|
37
|
+
def enable?
|
38
|
+
D13n.config[:'metric.app.state.exception.enable'] == 'true' || D13n.config[:'metric.app.state.exception.enable'] == true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
D13n::Metric::Instrumentation::Conductor.direct do
|
45
|
+
named :exception
|
46
|
+
|
47
|
+
depend_on do
|
48
|
+
D13n::Metric::Instrumentation::Exception.enable?
|
49
|
+
end
|
50
|
+
|
51
|
+
performances do
|
52
|
+
D13n.logger.info 'Installing Exeception instrumentation'
|
53
|
+
end
|
54
|
+
|
55
|
+
performances do
|
56
|
+
class StandardError
|
57
|
+
class << self
|
58
|
+
alias exception_without_d13n_instrumentation exception
|
59
|
+
alias exception exception_with_d13n_instrumentation
|
60
|
+
end
|
61
|
+
alias exception_without_d13n_instrumentation exception
|
62
|
+
alias exception exception_with_d13n_instrumentation
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module D13n::Metric::Instrumentation
|
2
|
+
module MiddlewareTracing
|
3
|
+
STREAM_STARTED_KEY = 'd13n.stream_started'.freeze unless defined?(STREAM_STARTED_KEY)
|
4
|
+
|
5
|
+
def call(env)
|
6
|
+
first_middleware = stream_started(env)
|
7
|
+
|
8
|
+
state = D13n::Metric::StreamState.st_get
|
9
|
+
|
10
|
+
begin
|
11
|
+
D13n::Metric::Stream.start(state, category, build_stream_options(env, first_middleware))
|
12
|
+
state.notify_rack_call(env) if first_middleware
|
13
|
+
result = (@target == self) ? traced_call(env) : @target.call(env)
|
14
|
+
|
15
|
+
if first_middleware
|
16
|
+
capture_response_attributes(state, result)
|
17
|
+
end
|
18
|
+
|
19
|
+
result
|
20
|
+
rescue Exception => e
|
21
|
+
D13n.logger.error(e)
|
22
|
+
raise e
|
23
|
+
ensure
|
24
|
+
D13n::Metric::Stream.stop(state)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def capture_response_code(state, result)
|
29
|
+
|
30
|
+
if result.is_a?(Array) && state.current_stream
|
31
|
+
state.current_stream.http_response_code = result[0]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
CONTENT_TYPE = 'Content-Type'.freeze unless defined?(CONTENT_TYPE)
|
36
|
+
|
37
|
+
def capture_response_content_type(state, result)
|
38
|
+
if result.is_a?(Array) && state.current_stream
|
39
|
+
_, headers, _ = result
|
40
|
+
state.current_stream.response_content_type = headers[CONTENT_TYPE]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
CONTENT_LENGTH = 'Content-Length'.freeze unless defined?(CONTENT_LENGTH)
|
45
|
+
|
46
|
+
def capture_response_content_length(state, result)
|
47
|
+
if result.is_a?(Array) && state.current_stream
|
48
|
+
_, headers, _ = result
|
49
|
+
state.current_stream.response_content_length = headers[CONTENT_LENGTH]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def capture_response_attributes(state, result)
|
54
|
+
capture_response_code(state, result)
|
55
|
+
capture_response_content_type(state, result)
|
56
|
+
capture_response_content_length(state, result)
|
57
|
+
end
|
58
|
+
#
|
59
|
+
# stream_name, apdex_started_at, request
|
60
|
+
#
|
61
|
+
|
62
|
+
def build_stream_options(env, first_middleware)
|
63
|
+
opts = @stream_options
|
64
|
+
opts = merge_first_middleware_options(opts, env) if first_middleware
|
65
|
+
opts
|
66
|
+
end
|
67
|
+
|
68
|
+
def merge_first_middleware_options(opts, env)
|
69
|
+
opts[:apdex_started_at] = parse_request_timestamp(env)
|
70
|
+
opts[:request] = ::Rack::Request.new(env) if defined?(::Rack)
|
71
|
+
opts
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_request_timestamp(env)
|
75
|
+
Time.now.to_f
|
76
|
+
end
|
77
|
+
|
78
|
+
def stream_started(env)
|
79
|
+
env[STREAM_STARTED_KEY] = true unless env[STREAM_STARTED_KEY]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
D13n::Metric::Instrumentation::Conductor.direct do
|
3
|
+
named :net_http
|
4
|
+
|
5
|
+
depend_on do
|
6
|
+
defined?(Net) && defined?(Net::HTTP)
|
7
|
+
end
|
8
|
+
|
9
|
+
performances do
|
10
|
+
D13n.logger.info 'Installing Net instrumentation'
|
11
|
+
require 'd13n/metric/http_clients/net_http_wrappers'
|
12
|
+
end
|
13
|
+
|
14
|
+
performances do
|
15
|
+
class Net::HTTP
|
16
|
+
def request_with_d13n_instrumentation(request, *args, &block)
|
17
|
+
return request_without_d13n_instrumentation(request, *args, &block) unless started?
|
18
|
+
wrapped_request = D13n::Metric::HTTPClients::NetHTTPClientRequest.new(self, request)
|
19
|
+
manager = D13n::Metric::Manager.instance
|
20
|
+
metric = manager.metric(:app_http)
|
21
|
+
|
22
|
+
if metric.nil?
|
23
|
+
D13n.logger.info "Null intrumentation metric class and ignore collection"
|
24
|
+
return request_without_d13n_instrumentation(request, *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
metric.instance(manager, direction: 'out').process(wrapped_request) do
|
28
|
+
request_without_d13n_instrumentation(request, *args, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
alias request_without_d13n_instrumentation request
|
33
|
+
alias request request_with_d13n_instrumentation
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module D13n::Metric::Instrumentation::Sinatra
|
2
|
+
module StreamNamer
|
3
|
+
extend self
|
4
|
+
|
5
|
+
SINATRA_ROUTE = 'sinatra.route'
|
6
|
+
UNKNOWN = 'unknown'.freeze
|
7
|
+
def for_route(env, request)
|
8
|
+
env[SINATRA_ROUTE]
|
9
|
+
end
|
10
|
+
|
11
|
+
def initial_stream_name(request)
|
12
|
+
stream_name(UNKNOWN, request)
|
13
|
+
end
|
14
|
+
|
15
|
+
ROOT = '.'.freeze
|
16
|
+
|
17
|
+
|
18
|
+
def stream_name(route_text, request)
|
19
|
+
verb = http_verb(request)
|
20
|
+
|
21
|
+
route_text = route_text.source if route_text.is_a?(Regexp)
|
22
|
+
name = route_text.gsub(%r{^[/^\\A]*(.*?)[/\$\?\\z]*$}, '\1')
|
23
|
+
name = ROOT if name.empty?
|
24
|
+
name = "#{verb}#{name}" unless verb.nil?
|
25
|
+
name
|
26
|
+
rescue => e
|
27
|
+
::D13n.logger.debug("#{e.class} : #{e.message} - Error encountered trying to identify Sinatra transaction name")
|
28
|
+
UNKNOWN
|
29
|
+
end
|
30
|
+
|
31
|
+
def http_verb(request)
|
32
|
+
request.request_method if request.respond_to?(:request_method)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'd13n/metric/instrumentation/controller_instrumentation'
|
2
|
+
require 'd13n/metric/instrumentation/sinatra/stream_namer'
|
3
|
+
require 'd13n/rack/metric_middleware'
|
4
|
+
D13n::Metric::Instrumentation::Conductor.direct do
|
5
|
+
named :sinatra
|
6
|
+
|
7
|
+
depend_on do
|
8
|
+
D13n.config[:'metric.app.http.in.sinatra.enable'] &&
|
9
|
+
defined?(::Sinatra) && defined?(::Sinatra::Base) &&
|
10
|
+
Sinatra::Base.private_method_defined?(:dispatch!) &&
|
11
|
+
Sinatra::Base.private_method_defined?(:process_route) &&
|
12
|
+
Sinatra::Base.private_method_defined?(:route_eval)
|
13
|
+
end
|
14
|
+
|
15
|
+
performances do
|
16
|
+
D13n.logger.info 'Installing Sinatra instrumentation'
|
17
|
+
end
|
18
|
+
|
19
|
+
performances do
|
20
|
+
::Sinatra::Base.class_eval do
|
21
|
+
include D13n::Metric::Instrumentation::Sinatra
|
22
|
+
alias dispatch_without_d13n_instrumentation dispatch!
|
23
|
+
alias dispatch! dispatch_with_d13n_instrumentation
|
24
|
+
|
25
|
+
alias process_route_without_d13n_instrumentation process_route
|
26
|
+
alias process_route process_route_with_d13n_instrumentation
|
27
|
+
|
28
|
+
alias route_eval_without_d13n_instrumentation route_eval
|
29
|
+
alias route_eval route_eval_with_d13n_instrumentation
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
performances do
|
35
|
+
if Sinatra::Base.respond_to?(:build)
|
36
|
+
require 'd13n/rack/metric_middleware'
|
37
|
+
|
38
|
+
::Sinatra::Base.class_eval do
|
39
|
+
class << self
|
40
|
+
alias build_without_d13n_instrumentation build
|
41
|
+
alias build build_with_d13n_instrumentation
|
42
|
+
end
|
43
|
+
end
|
44
|
+
else
|
45
|
+
D13n.logger.info("Skipping auto-injection of middleware for Sinatra - require Sinatra 1.2.1+")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
performances do
|
50
|
+
if defined?(::SinatraWebsocket) &&
|
51
|
+
defined?(::Sinatra::Request) &&
|
52
|
+
Sinatra::Request.respond_to?(:websocket)
|
53
|
+
::Sinatra::Base.class_eval do
|
54
|
+
class << self
|
55
|
+
alias websocket_without_d13n_instrumentation websocket
|
56
|
+
alias websocket websocket_with_d13n_instrumentation
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module D13n::Metric::Instrumentation
|
64
|
+
module Sinatra
|
65
|
+
include D13n::Metric::Instrumentation::ControllerInstrumentation
|
66
|
+
|
67
|
+
def self.included(descendance)
|
68
|
+
descendance.extend(ClassMethods)
|
69
|
+
end
|
70
|
+
|
71
|
+
module ClassMethods
|
72
|
+
def d13n_middlewares
|
73
|
+
middlewares = []
|
74
|
+
if D13n::Rack::MetricMiddleware.enabled?
|
75
|
+
middlewares << D13n::Rack::MetricMiddleware
|
76
|
+
end
|
77
|
+
middlewares
|
78
|
+
end
|
79
|
+
|
80
|
+
def websocket_with_d13n_instrumentation(*args, &block)
|
81
|
+
websocket_without_d13n_instrumentation(*args, &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_with_d13n_instrumentation(*args, &block)
|
85
|
+
if auto_middleware_enable?
|
86
|
+
d13n_middlewares.each do |middleware_kls|
|
87
|
+
try_to_use(self, middleware_kls)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
build_without_d13n_instrumentation(*args, &block)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def auto_middleware_enable?
|
97
|
+
D13n.config[:'metric.app.http.in.sinatra.auto_middleware.enable']
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def try_to_use(app, clazz)
|
102
|
+
if app.middleware.nil?
|
103
|
+
D13n.logger.debug("Failed to use middle for middleware missing in app")
|
104
|
+
return nil
|
105
|
+
end
|
106
|
+
has_middleware = app.middleware.any? { |info| info[0] == clazz }
|
107
|
+
app.use(clazz) unless has_middleware
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def process_route_with_d13n_instrumentation(*args, &block)
|
112
|
+
begin
|
113
|
+
env["d13n.last_route"] = args[0]
|
114
|
+
rescue => e
|
115
|
+
D13n.logger.debug("Failed determining last route in Sinatra", e)
|
116
|
+
end
|
117
|
+
|
118
|
+
process_route_without_d13n_instrumentation(*args, &block)
|
119
|
+
end
|
120
|
+
|
121
|
+
def route_eval_with_d13n_instrumentation(*args, &block)
|
122
|
+
begin
|
123
|
+
stream_name = StreamNamer.for_route(env, request)
|
124
|
+
|
125
|
+
unless stream_name.nil?
|
126
|
+
::D13n::Metric::Stream.set_default_stream_name("#{self.class.name}.#{stream_name}", :sinatra)
|
127
|
+
end
|
128
|
+
rescue => e
|
129
|
+
D13n.logger.debug("Failed during route_eval to set stream name", e)
|
130
|
+
end
|
131
|
+
|
132
|
+
route_eval_without_d13n_instrumentation(*args, &block)
|
133
|
+
end
|
134
|
+
|
135
|
+
def dispatch_with_d13n_instrumentation
|
136
|
+
request_params = get_request_params
|
137
|
+
name = StreamNamer.initial_stream_name(request)
|
138
|
+
filter_params = get_filter_parames(request_params)
|
139
|
+
perform_action_with_d13n_stream(:category => :sinatra,
|
140
|
+
:name => name,
|
141
|
+
:params => filter_params) do
|
142
|
+
dispatch_and_notice_errors_with_d13n_instrumentation
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def dispatch_and_notice_errors_with_d13n_instrumentation
|
147
|
+
dispatch_without_d13n_instrumentation
|
148
|
+
ensure
|
149
|
+
had_error = env.has_key?('sinatra.error')
|
150
|
+
::D13n::Metric::Manager.notice_error(env['sinatra.error']) if had_error
|
151
|
+
end
|
152
|
+
|
153
|
+
def get_request_params
|
154
|
+
begin
|
155
|
+
@request.params
|
156
|
+
rescue => e
|
157
|
+
D13n.logger.debug("Failed to get params from Rack request.", e)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def get_filter_parames(request_params)
|
162
|
+
request_params
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'd13n/metric/stream'
|
2
|
+
require 'd13n/metric/stream_state'
|
3
|
+
module D13n::Metric::Instrumentation
|
4
|
+
module WebSocketInstrumentation
|
5
|
+
def perform_websocket_with_d13n_stream(*args, &block)
|
6
|
+
state = D13n::Metric::StreamState.st_get
|
7
|
+
category = :websocket
|
8
|
+
|
9
|
+
trace_options = args.last.is_a?(Hash) ? args.last : {}
|
10
|
+
stream_options = create_stream_options(trace_options, category, state)
|
11
|
+
|
12
|
+
begin
|
13
|
+
stream = D13n::Metric::Stream.start(state, category, stream_options)
|
14
|
+
|
15
|
+
begin
|
16
|
+
yield
|
17
|
+
update_stream_data(state)
|
18
|
+
rescue => e
|
19
|
+
D13n::Metric::Manager.notice_error(e)
|
20
|
+
raise
|
21
|
+
ensure
|
22
|
+
D13n::Metric::Stream.stop(state)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
def create_stream_options(trace_options, categroy, state)
|
29
|
+
stream_options = {}
|
30
|
+
stream_options[:stream_name]
|
31
|
+
stream_options
|
32
|
+
end
|
33
|
+
|
34
|
+
def update_stream_data(state)
|
35
|
+
stream = state.current_stream
|
36
|
+
stream.http_response_code = 200
|
37
|
+
stream.request_content_length = request.delete(:request_content_length)
|
38
|
+
stream.response_content_type = "websocket"
|
39
|
+
stream.response_content_length = request.delete(:response_content_length)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'd13n/metric/conductor'
|
2
|
+
module D13n::Metric::Instrumentation
|
3
|
+
def load_instrumentation_files path
|
4
|
+
Dir.glob(path) do |file|
|
5
|
+
begin
|
6
|
+
require file.to_s
|
7
|
+
rescue => e
|
8
|
+
D13n.logger.warn "Error loading instrumentation file '#{file}':", e
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_instrumentation file
|
14
|
+
if @instrumented
|
15
|
+
load_instrumentation_files file
|
16
|
+
else
|
17
|
+
@instrumentation_files << file
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup_instrumentation
|
22
|
+
_setup_instrumentation
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def _setup_instrumentation
|
27
|
+
return if @instrumented
|
28
|
+
|
29
|
+
@instrumentation_files = []
|
30
|
+
|
31
|
+
@instrumented = true
|
32
|
+
|
33
|
+
instrumentation_path = File.expand_path(File.join(File.dirname(__FILE__), 'instrumentation'))
|
34
|
+
|
35
|
+
@instrumentation_files << File.join(instrumentation_path, '*.rb')
|
36
|
+
|
37
|
+
@instrumentation_files.each { |path| load_instrumentation_files(path) }
|
38
|
+
Conductor.perform!
|
39
|
+
D13n.logger.info "Finished instrumentation"
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'statsd-instrument'
|
2
|
+
require 'd13n/metric/metrics'
|
3
|
+
require 'd13n/metric/instrumentation'
|
4
|
+
require 'd13n/metric/stream'
|
5
|
+
module D13n::Metric
|
6
|
+
class MetricInitError < MetricError;end
|
7
|
+
class MetricArgError < MetricError; end
|
8
|
+
class MetricNotFoundError < MetricError; end
|
9
|
+
class InstrumentInitError < MetricError; end
|
10
|
+
class Manager
|
11
|
+
include D13n::Metric::Instrumentation
|
12
|
+
def self.start(channel='logger', opts={})
|
13
|
+
@instance ||= new(channel, opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.instance
|
17
|
+
@instance || start
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.notice_error(exception, opts={})
|
21
|
+
Stream.notice_error(exception, opts)
|
22
|
+
end
|
23
|
+
|
24
|
+
extend Forwardable
|
25
|
+
|
26
|
+
def_delegators StatsD, :measure, :increment, :gauge, :set
|
27
|
+
|
28
|
+
CHANNELS = ['udp', 'logger', 'null']
|
29
|
+
|
30
|
+
METRIC_MAPPING = {
|
31
|
+
'app_state' => AppStateMetric,
|
32
|
+
'app_http' => AppHttpMetric,
|
33
|
+
'app_database' => AppDatabaseMetric,
|
34
|
+
'biz_state' => BizStateMetric
|
35
|
+
}
|
36
|
+
|
37
|
+
attr_reader :channel, :backend
|
38
|
+
|
39
|
+
def initialize(channel, opts={})
|
40
|
+
self.channel = channel
|
41
|
+
@opts = opts
|
42
|
+
set_backend
|
43
|
+
setup_instrumentation
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_backend
|
47
|
+
@backend = if @channel == 'udp'
|
48
|
+
setup_udp_backend
|
49
|
+
elsif @channel == 'logger'
|
50
|
+
setup_logger_backend
|
51
|
+
else @channel == 'null'
|
52
|
+
setup_null_backend
|
53
|
+
end
|
54
|
+
D13n.logger.info "Using #{@backend.to_s} as channel in metric"
|
55
|
+
StatsD.backend = @backend
|
56
|
+
end
|
57
|
+
|
58
|
+
def setup_udp_backend
|
59
|
+
@host = @opts.fetch(:host, default_host)
|
60
|
+
@port = @opts.fetch(:port, default_port)
|
61
|
+
@backend_uri = "#{@host}:#{@port}"
|
62
|
+
@protocol = @opts.fetch(:protocol, default_protocol)
|
63
|
+
StatsD::Instrument::Backends::UDPBackend.new(@backend_uri, @protocol)
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup_logger_backend
|
67
|
+
@logger = @opts.fetch(:logger, D13n.logger)
|
68
|
+
raise InstrumentInitError.new "Missing Logger for logger backend" if @logger.nil?
|
69
|
+
StatsD::Instrument::Backends::LoggerBackend.new(@logger)
|
70
|
+
end
|
71
|
+
|
72
|
+
def setup_null_backend
|
73
|
+
StatsD::Instrument::Backends::NullBackend.new
|
74
|
+
end
|
75
|
+
|
76
|
+
def channel=(c)
|
77
|
+
@channel = c.to_s.downcase
|
78
|
+
raise MetricArgError.new("Invalid Instrument channel: #{c}") unless CHANNELS.include?(@channel)
|
79
|
+
end
|
80
|
+
|
81
|
+
def metric(type)
|
82
|
+
metric_for(type)
|
83
|
+
rescue MetricNotFoundError => e
|
84
|
+
D13n.logger.error "Instrument Metric Type #{type} Not Found in [#{METRIC_MAPPING.keys.join(',')}]"
|
85
|
+
return nil
|
86
|
+
end
|
87
|
+
|
88
|
+
def metric_for(type)
|
89
|
+
expected_metric = METRIC_MAPPING[type.to_s.downcase]
|
90
|
+
raise MetricNotFoundError.new "#{type} of metric not found!" if expected_metric.nil?
|
91
|
+
expected_metric
|
92
|
+
end
|
93
|
+
|
94
|
+
def default_host
|
95
|
+
D13n.config[:'service.metric.host'] || 'localhost'
|
96
|
+
end
|
97
|
+
|
98
|
+
def default_port
|
99
|
+
D13n.config[:'service.metric.port'] || 8125
|
100
|
+
end
|
101
|
+
|
102
|
+
def default_protocol
|
103
|
+
D13n.config[:'service.metric.protocol'] || :datadog
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|