puma-plugin-telemetry_too 0.0.1.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +115 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +190 -0
- data/Rakefile +10 -0
- data/docs/example-datadog_backlog_size.png +0 -0
- data/docs/example-datadog_queue_time.png +0 -0
- data/docs/examples.md +163 -0
- data/lib/puma/plugin/telemetry_too/config.rb +132 -0
- data/lib/puma/plugin/telemetry_too/data.rb +287 -0
- data/lib/puma/plugin/telemetry_too/formatters/json_formatter.rb +18 -0
- data/lib/puma/plugin/telemetry_too/formatters/logfmt_formatter.rb +16 -0
- data/lib/puma/plugin/telemetry_too/formatters/passthrough_formatter.rb +16 -0
- data/lib/puma/plugin/telemetry_too/targets/base_formatting_target.rb +46 -0
- data/lib/puma/plugin/telemetry_too/targets/datadog_statsd_target.rb +51 -0
- data/lib/puma/plugin/telemetry_too/targets/io_target.rb +27 -0
- data/lib/puma/plugin/telemetry_too/targets/log_target.rb +29 -0
- data/lib/puma/plugin/telemetry_too/transforms/cloud_watch_transform.rb +23 -0
- data/lib/puma/plugin/telemetry_too/transforms/l2met_transform.rb +46 -0
- data/lib/puma/plugin/telemetry_too/transforms/passthrough_transform.rb +16 -0
- data/lib/puma/plugin/telemetry_too/version.rb +9 -0
- data/lib/puma/plugin/telemetry_too.rb +118 -0
- data/lib/rack/request_queue_time_middleware.rb +60 -0
- metadata +97 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Puma
|
|
4
|
+
class Plugin
|
|
5
|
+
module TelemetryToo
|
|
6
|
+
module Transforms
|
|
7
|
+
# A pass-through transform - it returns the telemetry Hash it was given
|
|
8
|
+
class PassthroughTransform
|
|
9
|
+
def self.call(telemetry)
|
|
10
|
+
telemetry
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'puma'
|
|
4
|
+
require 'puma/plugin'
|
|
5
|
+
|
|
6
|
+
require 'puma/plugin/telemetry_too/version'
|
|
7
|
+
require 'puma/plugin/telemetry_too/data'
|
|
8
|
+
require 'puma/plugin/telemetry_too/targets/datadog_statsd_target'
|
|
9
|
+
require 'puma/plugin/telemetry_too/targets/io_target'
|
|
10
|
+
require 'puma/plugin/telemetry_too/targets/log_target'
|
|
11
|
+
require 'puma/plugin/telemetry_too/config'
|
|
12
|
+
|
|
13
|
+
module Puma
|
|
14
|
+
class Plugin
|
|
15
|
+
# TelemetryToo plugin for puma, supporting:
|
|
16
|
+
#
|
|
17
|
+
# - multiple targets, decide where to push puma telemetry information, i.e. datadog, cloudwatch, logs
|
|
18
|
+
# - filtering, select which metrics are interesting for you, extend when necessery
|
|
19
|
+
#
|
|
20
|
+
module TelemetryToo
|
|
21
|
+
class Error < StandardError; end
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
attr_writer :config
|
|
25
|
+
|
|
26
|
+
def config
|
|
27
|
+
@config ||= Config.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def configure
|
|
31
|
+
yield(config)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def build(launcher = nil)
|
|
35
|
+
socket_telemetry(puma_telemetry, launcher)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def puma_telemetry
|
|
41
|
+
stats = ::Puma.stats_hash
|
|
42
|
+
data_class = if stats.key?(:workers)
|
|
43
|
+
ClusteredData
|
|
44
|
+
else
|
|
45
|
+
WorkerData
|
|
46
|
+
end
|
|
47
|
+
data_class
|
|
48
|
+
.new(stats)
|
|
49
|
+
.metrics(config.puma_telemetry)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def socket_telemetry(telemetry, launcher)
|
|
53
|
+
return telemetry if launcher.nil?
|
|
54
|
+
return telemetry unless config.socket_telemetry?
|
|
55
|
+
|
|
56
|
+
telemetry.merge! SocketData.new(launcher.binder.ios, config.socket_parser)
|
|
57
|
+
.metrics
|
|
58
|
+
|
|
59
|
+
telemetry
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Contents of actual Puma Plugin
|
|
64
|
+
#
|
|
65
|
+
module PluginInstanceMethods
|
|
66
|
+
def start(launcher)
|
|
67
|
+
@launcher = launcher
|
|
68
|
+
|
|
69
|
+
unless Puma::Plugin::TelemetryToo.config.enabled?
|
|
70
|
+
log_writer.log 'plugin=telemetry msg="disabled, exiting..."'
|
|
71
|
+
return
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
log_writer.log 'plugin=telemetry msg="enabled, setting up runner..."'
|
|
75
|
+
|
|
76
|
+
in_background do
|
|
77
|
+
sleep Puma::Plugin::TelemetryToo.config.initial_delay
|
|
78
|
+
run!
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def run!
|
|
83
|
+
loop do
|
|
84
|
+
log_writer.debug 'plugin=telemetry msg="publish"'
|
|
85
|
+
|
|
86
|
+
call(Puma::Plugin::TelemetryToo.build(@launcher))
|
|
87
|
+
rescue Errno::EPIPE
|
|
88
|
+
# Occurs when trying to output to STDOUT while puma is shutting down
|
|
89
|
+
rescue StandardError => e
|
|
90
|
+
log_writer.error "plugin=telemetry err=#{e.class} msg=#{e.message.inspect}"
|
|
91
|
+
ensure
|
|
92
|
+
sleep Puma::Plugin::TelemetryToo.config.frequency
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def call(telemetry)
|
|
97
|
+
Puma::Plugin::TelemetryToo.config.targets.each do |target|
|
|
98
|
+
target.call(telemetry)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def log_writer
|
|
105
|
+
if Puma::Const::PUMA_VERSION.to_i < 6
|
|
106
|
+
@launcher.events
|
|
107
|
+
else
|
|
108
|
+
@launcher.log_writer
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
Puma::Plugin.create do
|
|
117
|
+
include Puma::Plugin::TelemetryToo::PluginInstanceMethods
|
|
118
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Measures the queue time (= time between receiving the request in downstream
|
|
4
|
+
# load balancer and starting request in ruby process)
|
|
5
|
+
class RequestQueueTimeMiddleware
|
|
6
|
+
ENV_KEY = 'rack.request_queue_time'
|
|
7
|
+
|
|
8
|
+
def initialize(app, statsd:, process: Process)
|
|
9
|
+
@app = app
|
|
10
|
+
@statsd = statsd
|
|
11
|
+
@process = process
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def call(env)
|
|
15
|
+
queue_time = measure_queue_time(env)
|
|
16
|
+
|
|
17
|
+
report_queue_time(queue_time)
|
|
18
|
+
|
|
19
|
+
env[ENV_KEY] = queue_time
|
|
20
|
+
|
|
21
|
+
@app.call(env)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def measure_queue_time(env)
|
|
27
|
+
start_time = queue_start(env)
|
|
28
|
+
|
|
29
|
+
return unless start_time
|
|
30
|
+
|
|
31
|
+
queue_time = request_start.to_f - start_time.to_f
|
|
32
|
+
|
|
33
|
+
queue_time unless queue_time.negative?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Get the content of the x-amzn-trace-id header, the epoch time in seconds.
|
|
37
|
+
# see also: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-request-tracing.html
|
|
38
|
+
def queue_start(env)
|
|
39
|
+
value = env['HTTP_X_AMZN_TRACE_ID']
|
|
40
|
+
# TODO: rewrite this line to please Rubocop
|
|
41
|
+
# rubocop:disable Style/SafeNavigationChainLength
|
|
42
|
+
value&.split('Root=')&.last&.split('-')&.fetch(1)&.to_i(16)
|
|
43
|
+
# rubocop:enable Style/SafeNavigationChainLength
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def request_start
|
|
47
|
+
@process.clock_gettime(Process::CLOCK_REALTIME)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def report_queue_time(queue_time)
|
|
51
|
+
return if queue_time.nil?
|
|
52
|
+
|
|
53
|
+
@statsd.timing('queue.time', queue_time)
|
|
54
|
+
|
|
55
|
+
return unless defined?(Datadog) && Datadog.respond_to?(:tracer)
|
|
56
|
+
|
|
57
|
+
span = Datadog.tracer.active_root_span
|
|
58
|
+
span&.set_tag('request.queue_time', queue_time)
|
|
59
|
+
end
|
|
60
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: puma-plugin-telemetry_too
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1.alpha1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Leszek Zalewski
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: puma
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "<"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '8'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "<"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '8'
|
|
26
|
+
description: |
|
|
27
|
+
NOTE: This is a fork of puma-plugin-telemetry, modified to:
|
|
28
|
+
|
|
29
|
+
- Support Puma 7
|
|
30
|
+
- Add LogTarget, with custom formatter: and transform: options
|
|
31
|
+
- Warn about socket telemetry on unsupported platforms
|
|
32
|
+
|
|
33
|
+
Puma plugin which should be able to handle all your metric needs regarding your webserver:
|
|
34
|
+
|
|
35
|
+
- ability to publish basic puma statistics (like queue backlog) to both logs and datadog
|
|
36
|
+
- ability to add custom target whenever you need it
|
|
37
|
+
- ability to monitor puma socket listen queue (!)
|
|
38
|
+
- ability to report requests queue time via custom rack middleware - the time request spent between being accepted by Load Balancer and start of its processing by Puma worker
|
|
39
|
+
email:
|
|
40
|
+
- tnt@babbel.com
|
|
41
|
+
executables: []
|
|
42
|
+
extensions: []
|
|
43
|
+
extra_rdoc_files: []
|
|
44
|
+
files:
|
|
45
|
+
- ".rspec"
|
|
46
|
+
- ".rubocop.yml"
|
|
47
|
+
- ".tool-versions"
|
|
48
|
+
- CHANGELOG.md
|
|
49
|
+
- CODE_OF_CONDUCT.md
|
|
50
|
+
- LICENSE.txt
|
|
51
|
+
- README.md
|
|
52
|
+
- Rakefile
|
|
53
|
+
- docs/example-datadog_backlog_size.png
|
|
54
|
+
- docs/example-datadog_queue_time.png
|
|
55
|
+
- docs/examples.md
|
|
56
|
+
- lib/puma/plugin/telemetry_too.rb
|
|
57
|
+
- lib/puma/plugin/telemetry_too/config.rb
|
|
58
|
+
- lib/puma/plugin/telemetry_too/data.rb
|
|
59
|
+
- lib/puma/plugin/telemetry_too/formatters/json_formatter.rb
|
|
60
|
+
- lib/puma/plugin/telemetry_too/formatters/logfmt_formatter.rb
|
|
61
|
+
- lib/puma/plugin/telemetry_too/formatters/passthrough_formatter.rb
|
|
62
|
+
- lib/puma/plugin/telemetry_too/targets/base_formatting_target.rb
|
|
63
|
+
- lib/puma/plugin/telemetry_too/targets/datadog_statsd_target.rb
|
|
64
|
+
- lib/puma/plugin/telemetry_too/targets/io_target.rb
|
|
65
|
+
- lib/puma/plugin/telemetry_too/targets/log_target.rb
|
|
66
|
+
- lib/puma/plugin/telemetry_too/transforms/cloud_watch_transform.rb
|
|
67
|
+
- lib/puma/plugin/telemetry_too/transforms/l2met_transform.rb
|
|
68
|
+
- lib/puma/plugin/telemetry_too/transforms/passthrough_transform.rb
|
|
69
|
+
- lib/puma/plugin/telemetry_too/version.rb
|
|
70
|
+
- lib/rack/request_queue_time_middleware.rb
|
|
71
|
+
homepage: https://github.com/stevenharman/puma-plugin-telemetry_too
|
|
72
|
+
licenses:
|
|
73
|
+
- MIT
|
|
74
|
+
metadata:
|
|
75
|
+
homepage_uri: https://github.com/stevenharman/puma-plugin-telemetry_too
|
|
76
|
+
source_code_uri: https://github.com/stevenharman/puma-plugin-telemetry_too
|
|
77
|
+
changelog_uri: https://github.com/stevenharman/puma-plugin-telemetry_too/blob/main/CHANGELOG.md
|
|
78
|
+
github_repo: ssh://github.com/stevenharman/puma-plugin-telemetry_too
|
|
79
|
+
rubygems_mfa_required: 'true'
|
|
80
|
+
rdoc_options: []
|
|
81
|
+
require_paths:
|
|
82
|
+
- lib
|
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - ">="
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: 3.2.0
|
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '0'
|
|
93
|
+
requirements: []
|
|
94
|
+
rubygems_version: 3.6.9
|
|
95
|
+
specification_version: 4
|
|
96
|
+
summary: Puma plugin, adding ability to publish various metrics to your prefered targets.
|
|
97
|
+
test_files: []
|