File tree Expand file tree Collapse file tree 6 files changed +104
-6
lines changed
Expand file tree Collapse file tree 6 files changed +104
-6
lines changed Original file line number Diff line number Diff line change @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
88## [ Unreleased]
99
10+ ## [ 1.1.0 Alpha]
11+
12+ ### Added
13+
14+ Socket telemetry, and to be more precise new metric: ` sockets.backlog ` . If enabled it will
15+ pull information from Puma sockets about the state of their backlogs (requests waiting to
16+ be acknowledged by Puma). It will be exposed under ` sockets-backlog ` metric.
17+
18+ You can enable and test it via ` config.sockets_telemetry! ` option.
19+
1020## [ 1.0.0] - 2021-09-08
1121### Added
1222- Release to Github Packages
Original file line number Diff line number Diff line change 11PATH
22 remote: .
33 specs:
4- puma-plugin-telemetry (0.3.1 )
4+ puma-plugin-telemetry (1.1.0.alpha )
55 puma (>= 5.0 )
66
77GEM
1414 parallel (1.20.1 )
1515 parser (3.0.2.0 )
1616 ast (~> 2.4.1 )
17- puma (5.4.0 )
17+ puma (5.5.2 )
1818 nio4r (~> 2.0 )
1919 rack (2.2.3 )
2020 rainbow (3.0.0 )
Original file line number Diff line number Diff line change @@ -30,8 +30,8 @@ def configure
3030 yield ( config )
3131 end
3232
33- def build
34- puma_telemetry
33+ def build ( launcher = nil )
34+ socket_telemetry ( puma_telemetry , launcher )
3535 end
3636
3737 private
@@ -47,6 +47,16 @@ def puma_telemetry
4747 . new ( stats )
4848 . metrics ( config . puma_telemetry )
4949 end
50+
51+ def socket_telemetry ( telemetry , launcher )
52+ return telemetry if launcher . nil?
53+ return telemetry unless config . socket_telemetry?
54+
55+ telemetry . merge! SocketData . new ( launcher . binder . ios )
56+ . metrics
57+
58+ telemetry
59+ end
5060 end
5161
5262 # Contents of actual Puma Plugin
@@ -71,7 +81,7 @@ def run!
7181 loop do
7282 @launcher . events . debug "plugin=telemetry msg=\" publish\" "
7383
74- call ( Puma ::Plugin ::Telemetry . build )
84+ call ( Puma ::Plugin ::Telemetry . build ( @launcher ) )
7585 rescue Errno ::EPIPE
7686 # Occurs when trying to output to STDOUT while puma is shutting down
7787 rescue StandardError => e
Original file line number Diff line number Diff line change @@ -58,18 +58,31 @@ class Config
5858 # - default: DEFAULT_PUMA_TELEMETRY
5959 attr_accessor :puma_telemetry
6060
61+ # Whenever to publish socket telemetry.
62+ # - default: false
63+ attr_accessor :socket_telemetry
64+
6165 def initialize
6266 @enabled = false
6367 @initial_delay = 5
6468 @frequency = 5
6569 @targets = [ ]
6670 @puma_telemetry = DEFAULT_PUMA_TELEMETRY
71+ @socket_telemetry = false
6772 end
6873
6974 def enabled?
7075 !!@enabled
7176 end
7277
78+ def socket_telemetry!
79+ @socket_telemetry = true
80+ end
81+
82+ def socket_telemetry?
83+ @socket_telemetry
84+ end
85+
7386 def add_target ( name_or_target , **args )
7487 return @targets . push ( name_or_target ) unless name_or_target . is_a? ( Symbol )
7588
Original file line number Diff line number Diff line change @@ -95,6 +95,71 @@ def sum_stat(stat)
9595 end
9696 end
9797 end
98+
99+ # Pulls TCP INFO data from socket
100+ class SocketData
101+ UNACKED_REGEXP = /\ unacked=(?<unacked>\d +)\ / . freeze
102+
103+ def initialize ( ios )
104+ @sockets = ios . select { |io | io . respond_to? ( :getsockopt ) }
105+ end
106+
107+ # Number of unacknowledged connections in the sockets, which
108+ # we know as socket backlog.
109+ #
110+ # The Socket::Option returned by `getsockopt` doesn't provide
111+ # any kind of accessors for data inside. It decodes it on demand
112+ # for `inspect` as strings in C implementation. It looks like
113+ #
114+ # #<Socket::Option: INET TCP INFO state=LISTEN
115+ # ca_state=Open
116+ # retransmits=0
117+ # probes=0
118+ # backoff=0
119+ # options=0
120+ # rto=0.000000s
121+ # ato=0.000000s
122+ # snd_mss=0
123+ # rcv_mss=0
124+ # unacked=0
125+ # sacked=5
126+ # lost=0
127+ # retrans=0
128+ # fackets=0
129+ # last_data_sent=0.000s
130+ # last_ack_sent=0.000s
131+ # last_data_recv=0.000s
132+ # last_ack_recv=0.000s
133+ # pmtu=0
134+ # rcv_ssthresh=0
135+ # rtt=0.000000s
136+ # rttvar=0.000000s
137+ # snd_ssthresh=0
138+ # snd_cwnd=10
139+ # advmss=0
140+ # reordering=3
141+ # rcv_rtt=0.000000s
142+ # rcv_space=0
143+ # total_retrans=0
144+ # (128 bytes too long)>
145+ #
146+ # That's why we have to pull the `unacked` field by parsing
147+ # `inspect` output, instead of using something like `opt.unacked`
148+ def unacked
149+ @sockets . sum do |socket |
150+ tcp_info = socket . getsockopt ( Socket ::SOL_TCP , Socket ::TCP_INFO ) . inspect
151+ tcp_match = tcp_info . match ( UNACKED_REGEXP )
152+
153+ tcp_match [ :unacked ] . to_i
154+ end
155+ end
156+
157+ def metrics
158+ {
159+ "sockets.backlog" => unacked
160+ }
161+ end
162+ end
98163 end
99164 end
100165end
Original file line number Diff line number Diff line change 33module Puma
44 class Plugin
55 module Telemetry
6- VERSION = "1.0.0 "
6+ VERSION = "1.1.0.alpha "
77 end
88 end
99end
You can’t perform that action at this time.
0 commit comments