puma-plugin-statsd 0.2.0 → 1.2.1
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 +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +25 -6
- data/lib/puma/plugin/statsd.rb +65 -34
- metadata +4 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb512a32b788a2df3fc7f9f222e7dcb510fdbda09bb1bb278466978d2f5b511d
|
4
|
+
data.tar.gz: 6274f07b78d32a6bddbc5d6d823114f6171df7fb3131186e35fbdd9416244ce1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c568951db0c140e934d4cd40103c8b98160da02aeeda6b2549dd59a415ee2ee59ea171f6d818150fdbb66c99b88a912690c31f9bc3bc0715dc7478440136e76a
|
7
|
+
data.tar.gz: 2af0724eb7a83bae47caed6c3009a5fa5ed2d0ab98b2c98be250c03636750bdf48788f69fe8bd04fb83a7656fb15174ab356edd0581eed072e780b4fa0855aa8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.2.1 2021-01-11
|
4
|
+
|
5
|
+
* Remove json from the gemspec
|
6
|
+
|
7
|
+
## 1.2.0 2021-01-07
|
8
|
+
|
9
|
+
* New metrics: old_workers (PR #[21](https://github.com/yob/puma-plugin-statsd/pull/21)) and requsts_count (PR #[28](https://github.com/yob/puma-plugin-statsd/pull/28))
|
10
|
+
* Require json at runtime to be extra sure we don't load the wrong version before bundler has initialised the LOAD_PATH
|
11
|
+
|
12
|
+
## 1.1.0 2021-01-03
|
13
|
+
|
14
|
+
* Assume localhost for statsd host (PR #[20](https://github.com/yob/puma-plugin-statsd/pull/20))
|
15
|
+
|
16
|
+
## 1.0.0 2020-11-03
|
17
|
+
|
18
|
+
* Added option to specify arbitrary datadog tags (PR #[18](https://github.com/yob/puma-plugin-statsd/pull/18))
|
19
|
+
|
20
|
+
## 0.3.0 2020-09-24
|
21
|
+
|
22
|
+
* Support puma 5.x
|
23
|
+
|
3
24
|
## 0.2.0 2020-02-29
|
4
25
|
|
5
26
|
* Added option to prefix stats metric (via STATSD_METRIC_PREFIX env var)
|
data/README.md
CHANGED
@@ -37,12 +37,14 @@ plugin :statsd
|
|
37
37
|
|
38
38
|
## Usage
|
39
39
|
|
40
|
-
|
40
|
+
By default the plugin assumes statsd is available at 127.0.0.1. If that's true in your environment, just start puma like normal:
|
41
41
|
|
42
42
|
```
|
43
|
-
|
43
|
+
bundle exec puma
|
44
44
|
```
|
45
45
|
|
46
|
+
If statsd isn't on 127.0.0.1 or the port is non-standard, you can configure them using optional environment variables:
|
47
|
+
|
46
48
|
```
|
47
49
|
STATSD_HOST=127.0.0.1 STATSD_PORT=9125 bundle exec puma
|
48
50
|
```
|
@@ -53,9 +55,24 @@ metric tags are a non-standard addition to the statsd protocol, supported by
|
|
53
55
|
the datadog "dogstatsd" server.
|
54
56
|
|
55
57
|
Should you be reporting the puma metrics to a dogstatsd server, you can set
|
56
|
-
tags via the following
|
58
|
+
tags via the following three environment variables.
|
59
|
+
|
60
|
+
#### DD_TAGS
|
61
|
+
|
62
|
+
`DD_TAGS`: Set this to a space-separated list of tags, using the
|
63
|
+
[datadog agent standard format](https://docs.datadoghq.com/agent/docker/?tab=standard#global-options).
|
64
|
+
|
65
|
+
For example, you could set this environment variable to set three datadog tags,
|
66
|
+
and then you can filter by in the datadog interface:
|
57
67
|
|
58
|
-
|
68
|
+
```bash
|
69
|
+
export DD_TAGS="env:test simple-tag-0 tag-key-1:tag-value-1"
|
70
|
+
bundle exec rails server
|
71
|
+
```
|
72
|
+
|
73
|
+
#### MY_POD_NAME
|
74
|
+
|
75
|
+
`MY_POD_NAME`: Set a `pod_name` tag to the metrics. The `MY_POD_NAME`
|
59
76
|
environment variable is recommended in the datadog kubernetes setup
|
60
77
|
documentation, and for puma apps deployed to kubernetes it's very helpful to
|
61
78
|
have the option to report on specific pods.
|
@@ -70,7 +87,9 @@ env:
|
|
70
87
|
fieldPath: metadata.name
|
71
88
|
```
|
72
89
|
|
73
|
-
|
90
|
+
#### STATSD_GROUPING
|
91
|
+
|
92
|
+
`STATSD_GROUPING`: add a `grouping` tag to the metrics, with a value equal to
|
74
93
|
the environment variable value. This is particularly helpful in a kubernetes
|
75
94
|
deployment where each pod has a unique name but you want the option to group
|
76
95
|
metrics across all pods in a deployment. Setting this on the pods in a
|
@@ -100,7 +119,7 @@ Start puma:
|
|
100
119
|
Throw some traffic at it, either with curl or a tool like ab:
|
101
120
|
|
102
121
|
curl http://127.0.0.1:9292/
|
103
|
-
ab -n 10000 -c 20 http://127.0.0.1:9292/
|
122
|
+
ab -n 10000 -c 20 http://127.0.0.1:9292/
|
104
123
|
|
105
124
|
Watch the output of the UDP server process - you should see statsd data printed to stdout.
|
106
125
|
|
data/lib/puma/plugin/statsd.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# coding: utf-8, frozen_string_literal: true
|
2
|
-
require "json"
|
3
2
|
require "puma"
|
4
3
|
require "puma/plugin"
|
5
4
|
require 'socket'
|
@@ -12,20 +11,13 @@ class StatsdConnector
|
|
12
11
|
attr_reader :host, :port
|
13
12
|
|
14
13
|
def initialize
|
15
|
-
@host = ENV.fetch(ENV_NAME,
|
14
|
+
@host = ENV.fetch(ENV_NAME, "127.0.0.1")
|
16
15
|
@port = ENV.fetch("STATSD_PORT", 8125)
|
17
16
|
end
|
18
17
|
|
19
|
-
def
|
20
|
-
!!host
|
21
|
-
end
|
22
|
-
|
23
|
-
def send(metric_name:, value:, type:, tags: {})
|
18
|
+
def send(metric_name:, value:, type:, tags: nil)
|
24
19
|
data = "#{metric_name}:#{value}|#{STATSD_TYPES.fetch(type)}"
|
25
|
-
|
26
|
-
tag_str = tags.map { |k,v| "#{k}:#{v}" }.join(",")
|
27
|
-
data = "#{data}|##{tag_str}"
|
28
|
-
end
|
20
|
+
data = "#{data}|##{tags}" unless tags.nil?
|
29
21
|
|
30
22
|
socket = UDPSocket.new
|
31
23
|
socket.send(data, 0, host, port)
|
@@ -52,6 +44,10 @@ class PumaStats
|
|
52
44
|
@stats.fetch(:booted_workers, 1)
|
53
45
|
end
|
54
46
|
|
47
|
+
def old_workers
|
48
|
+
@stats.fetch(:old_workers, 0)
|
49
|
+
end
|
50
|
+
|
55
51
|
def running
|
56
52
|
if clustered?
|
57
53
|
@stats[:worker_status].map { |s| s[:last_status].fetch(:running, 0) }.inject(0, &:+)
|
@@ -83,32 +79,31 @@ class PumaStats
|
|
83
79
|
@stats.fetch(:max_threads, 0)
|
84
80
|
end
|
85
81
|
end
|
86
|
-
end
|
87
82
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
83
|
+
def requests_count
|
84
|
+
if clustered?
|
85
|
+
@stats[:worker_status].map { |s| s[:last_status].fetch(:requests_count, 0) }.inject(0, &:+)
|
86
|
+
else
|
87
|
+
@stats.fetch(:requests_count, 0)
|
88
|
+
end
|
92
89
|
end
|
90
|
+
end
|
93
91
|
|
92
|
+
Puma::Plugin.create do
|
94
93
|
# We can start doing something when we have a launcher:
|
95
94
|
def start(launcher)
|
96
95
|
@launcher = launcher
|
97
96
|
|
98
97
|
@statsd = ::StatsdConnector.new
|
99
|
-
|
100
|
-
@launcher.events.debug "statsd: enabled (host: #{@statsd.host})"
|
101
|
-
|
102
|
-
# Fetch global metric prefix from env variable
|
103
|
-
@metric_prefix = ENV.fetch("STATSD_METRIC_PREFIX", nil)
|
104
|
-
if @metric_prefix && !@metric_prefix.end_with?(::StatsdConnector::METRIC_DELIMETER)
|
105
|
-
@metric_prefix += ::StatsdConnector::METRIC_DELIMETER
|
106
|
-
end
|
98
|
+
@launcher.events.debug "statsd: enabled (host: #{@statsd.host})"
|
107
99
|
|
108
|
-
|
109
|
-
|
110
|
-
|
100
|
+
# Fetch global metric prefix from env variable
|
101
|
+
@metric_prefix = ENV.fetch("STATSD_METRIC_PREFIX", nil)
|
102
|
+
if @metric_prefix && !@metric_prefix.end_with?(::StatsdConnector::METRIC_DELIMETER)
|
103
|
+
@metric_prefix += ::StatsdConnector::METRIC_DELIMETER
|
111
104
|
end
|
105
|
+
|
106
|
+
register_hooks
|
112
107
|
end
|
113
108
|
|
114
109
|
private
|
@@ -117,19 +112,51 @@ Puma::Plugin.create do
|
|
117
112
|
in_background(&method(:stats_loop))
|
118
113
|
end
|
119
114
|
|
120
|
-
|
121
|
-
|
115
|
+
if Puma.respond_to?(:stats_hash)
|
116
|
+
def fetch_stats
|
117
|
+
Puma.stats_hash
|
118
|
+
end
|
119
|
+
else
|
120
|
+
def fetch_stats
|
121
|
+
require "json"
|
122
|
+
stats = Puma.stats
|
123
|
+
JSON.parse(stats, symbolize_names: true)
|
124
|
+
end
|
122
125
|
end
|
123
126
|
|
124
|
-
def
|
125
|
-
|
127
|
+
def environment_variable_tags
|
128
|
+
# Tags are separated by spaces, and while they are normally a tag and
|
129
|
+
# value separated by a ':', they can also just be tagged without any
|
130
|
+
# associated value.
|
131
|
+
#
|
132
|
+
# Examples: simple-tag-0 tag-key-1:tag-value-1
|
133
|
+
#
|
134
|
+
tags = []
|
135
|
+
|
126
136
|
if ENV.has_key?("MY_POD_NAME")
|
127
|
-
tags
|
137
|
+
tags << "pod_name:#{ENV['MY_POD_NAME']}"
|
128
138
|
end
|
139
|
+
|
129
140
|
if ENV.has_key?("STATSD_GROUPING")
|
130
|
-
tags
|
141
|
+
tags << "grouping:#{ENV['STATSD_GROUPING']}"
|
131
142
|
end
|
132
|
-
|
143
|
+
|
144
|
+
# Standardised datadog tag attributes, so that we can share the metric
|
145
|
+
# tags with the application running
|
146
|
+
#
|
147
|
+
# https://docs.datadoghq.com/agent/docker/?tab=standard#global-options
|
148
|
+
#
|
149
|
+
if ENV.has_key?("DD_TAGS")
|
150
|
+
ENV["DD_TAGS"].split(/\s+/).each do |t|
|
151
|
+
tags << t
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Return nil if we have no environment variable tags. This way we don't
|
156
|
+
# send an unnecessary '|' on the end of each stat
|
157
|
+
return nil if tags.empty?
|
158
|
+
|
159
|
+
tags.join(",")
|
133
160
|
end
|
134
161
|
|
135
162
|
def prefixed_metric_name(puma_metric)
|
@@ -138,6 +165,8 @@ Puma::Plugin.create do
|
|
138
165
|
|
139
166
|
# Send data to statsd every few seconds
|
140
167
|
def stats_loop
|
168
|
+
tags = environment_variable_tags
|
169
|
+
|
141
170
|
sleep 5
|
142
171
|
loop do
|
143
172
|
@launcher.events.debug "statsd: notify statsd"
|
@@ -145,10 +174,12 @@ Puma::Plugin.create do
|
|
145
174
|
stats = ::PumaStats.new(fetch_stats)
|
146
175
|
@statsd.send(metric_name: prefixed_metric_name("puma.workers"), value: stats.workers, type: :gauge, tags: tags)
|
147
176
|
@statsd.send(metric_name: prefixed_metric_name("puma.booted_workers"), value: stats.booted_workers, type: :gauge, tags: tags)
|
177
|
+
@statsd.send(metric_name: prefixed_metric_name("puma.old_workers"), value: stats.old_workers, type: :gauge, tags: tags)
|
148
178
|
@statsd.send(metric_name: prefixed_metric_name("puma.running"), value: stats.running, type: :gauge, tags: tags)
|
149
179
|
@statsd.send(metric_name: prefixed_metric_name("puma.backlog"), value: stats.backlog, type: :gauge, tags: tags)
|
150
180
|
@statsd.send(metric_name: prefixed_metric_name("puma.pool_capacity"), value: stats.pool_capacity, type: :gauge, tags: tags)
|
151
181
|
@statsd.send(metric_name: prefixed_metric_name("puma.max_threads"), value: stats.max_threads, type: :gauge, tags: tags)
|
182
|
+
@statsd.send(metric_name: prefixed_metric_name("puma.requests_count"), value: stats.requests_count, type: :gauge, tags: tags)
|
152
183
|
rescue StandardError => e
|
153
184
|
@launcher.events.error "! statsd: notify stats failed:\n #{e.to_s}\n #{e.backtrace.join("\n ")}"
|
154
185
|
ensure
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma-plugin-statsd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Healy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: puma
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '3.12'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '6'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,21 +29,7 @@ dependencies:
|
|
29
29
|
version: '3.12'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: json
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - ">="
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '0'
|
40
|
-
type: :runtime
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - ">="
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0'
|
32
|
+
version: '6'
|
47
33
|
- !ruby/object:Gem::Dependency
|
48
34
|
name: bundler
|
49
35
|
requirement: !ruby/object:Gem::Requirement
|