From 44d440c247f87cf74beef4c697aa25261e04248e Mon Sep 17 00:00:00 2001 From: Richard Hurt Date: Thu, 10 Apr 2025 05:09:09 -0400 Subject: [PATCH 1/4] Fix sender.rb specs --- lib/puma_cloudwatch/metrics/sender.rb | 13 ++++-- spec/puma_cloudwatch/metrics/sender_spec.rb | 48 ++++++++++++++------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/lib/puma_cloudwatch/metrics/sender.rb b/lib/puma_cloudwatch/metrics/sender.rb index 6dfd052..c182c63 100644 --- a/lib/puma_cloudwatch/metrics/sender.rb +++ b/lib/puma_cloudwatch/metrics/sender.rb @@ -60,13 +60,18 @@ def call # Output example: # # [{:metric_name=>"backlog", - # :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}}, + # :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, + # :storage_resolution=>60}, # {:metric_name=>"running", - # :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}}, + # :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, + # :storage_resolution=>60}, # {:metric_name=>"pool_capacity", - # :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}}, + # :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}, + # :storage_resolution=>60}, # {:metric_name=>"max_threads", - # :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}}] + # :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}, + # :storage_resolution=>60 + # }] # # Resources: # pool_capcity and max_threads are the important metrics diff --git a/spec/puma_cloudwatch/metrics/sender_spec.rb b/spec/puma_cloudwatch/metrics/sender_spec.rb index fb6c1a8..1566d56 100644 --- a/spec/puma_cloudwatch/metrics/sender_spec.rb +++ b/spec/puma_cloudwatch/metrics/sender_spec.rb @@ -14,17 +14,25 @@ data = sender.metric_data expect(data).to eq( [{:metric_name=>"backlog", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>1, :sum=>0, :minimum=>0, :maximum=>0}}, + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>1, :sum=>0, :minimum=>0, :maximum=>0}, + :storage_resolution=>60 + }, {:metric_name=>"running", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>1, :sum=>16, :minimum=>16, :maximum=>16}}, + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>1, :sum=>16, :minimum=>16, :maximum=>16}, + :storage_resolution=>60 + }, {:metric_name=>"pool_capacity", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>1, :sum=>8, :minimum=>8, :maximum=>8}}, + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>1, :sum=>8, :minimum=>8, :maximum=>8}, + :storage_resolution=>60 + }, {:metric_name=>"max_threads", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>1, :sum=>16, :minimum=>16, :maximum=>16}}] + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>1, :sum=>16, :minimum=>16, :maximum=>16}, + :storage_resolution=>60 + }] ) end @@ -49,17 +57,25 @@ data = sender.metric_data expect(data).to eq( [{:metric_name=>"backlog", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}}, + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, + :storage_resolution=>60 + }, {:metric_name=>"running", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}}, + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, + :storage_resolution=>60 + }, {:metric_name=>"pool_capacity", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}}, + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}, + :storage_resolution=>60 + }, {:metric_name=>"max_threads", - :dimensions=>[{:name=>"App", :value=>"demo-puma"}], - :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}}] + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>2, :sum=>32, :minimum=>16, :maximum=>16}, + :storage_resolution=>60 + }] ) end From 55d6350561c192f90e3ef8e16d1a309d3134fcc2 Mon Sep 17 00:00:00 2001 From: Richard Hurt Date: Thu, 10 Apr 2025 07:49:20 -0400 Subject: [PATCH 2/4] Fix fetcher specs --- spec/puma_cloudwatch/metrics/fetcher_spec.rb | 31 ++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/spec/puma_cloudwatch/metrics/fetcher_spec.rb b/spec/puma_cloudwatch/metrics/fetcher_spec.rb index 39c062d..84a62d4 100644 --- a/spec/puma_cloudwatch/metrics/fetcher_spec.rb +++ b/spec/puma_cloudwatch/metrics/fetcher_spec.rb @@ -1,11 +1,32 @@ +# RSpec.describe PumaCloudwatch::Metrics::Fetcher do +# subject(:fetcher) { described_class.new(control_url: '', control_auth_token: '') } + +# describe "fetcher" do +# it "call" do +# fake_data = {"fake" => "data"} +# json_data = JSON.dump(fake_data) +# allow(Socket).to receive(:unix).and_return(json_data) + +# stats = fetcher.call +# expect(stats).to eq(fake_data) +# end +# end +# end + + RSpec.describe PumaCloudwatch::Metrics::Fetcher do - subject(:fetcher) { described_class.new(control_url: '', control_auth_token: '') } + subject(:fetcher) { described_class.new(control_url: 'unix:///tmp/fake.sock', control_auth_token: '') } describe "fetcher" do - it "call" do - fake_data = {"fake" => "data"} - json_data = JSON.dump(fake_data) - allow(Socket).to receive(:unix).and_return(json_data) + it "calls and parses the socket response" do + fake_data = { "fake" => "data" } + response_body = "HTTP/1.0 200 OK\r\n\r\n#{JSON.dump(fake_data)}" + + mock_socket = double("socket") + allow(mock_socket).to receive(:print) + allow(mock_socket).to receive(:read).and_return(response_body) + + allow(Socket).to receive(:unix).and_yield(mock_socket) stats = fetcher.call expect(stats).to eq(fake_data) From 2e5ef827c391cf7743932b653b613536b5d6dd6b Mon Sep 17 00:00:00 2001 From: Richard Hurt Date: Thu, 10 Apr 2025 07:50:41 -0400 Subject: [PATCH 3/4] Remove comments --- spec/puma_cloudwatch/metrics/fetcher_spec.rb | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/spec/puma_cloudwatch/metrics/fetcher_spec.rb b/spec/puma_cloudwatch/metrics/fetcher_spec.rb index 84a62d4..31df499 100644 --- a/spec/puma_cloudwatch/metrics/fetcher_spec.rb +++ b/spec/puma_cloudwatch/metrics/fetcher_spec.rb @@ -1,19 +1,3 @@ -# RSpec.describe PumaCloudwatch::Metrics::Fetcher do -# subject(:fetcher) { described_class.new(control_url: '', control_auth_token: '') } - -# describe "fetcher" do -# it "call" do -# fake_data = {"fake" => "data"} -# json_data = JSON.dump(fake_data) -# allow(Socket).to receive(:unix).and_return(json_data) - -# stats = fetcher.call -# expect(stats).to eq(fake_data) -# end -# end -# end - - RSpec.describe PumaCloudwatch::Metrics::Fetcher do subject(:fetcher) { described_class.new(control_url: 'unix:///tmp/fake.sock', control_auth_token: '') } From cf6b6e69106f682660f2a8a33fa91b778c84f7b0 Mon Sep 17 00:00:00 2001 From: Richard Hurt Date: Thu, 10 Apr 2025 08:07:51 -0400 Subject: [PATCH 4/4] Add stat --- README.md | 3 ++- lib/puma_cloudwatch/metrics/parser.rb | 3 ++- lib/puma_cloudwatch/metrics/sender.rb | 4 ++++ spec/puma_cloudwatch/metrics/parser_spec.rb | 6 +++++- spec/puma_cloudwatch/metrics/sender_spec.rb | 12 ++++++++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9ace93b..e5755d9 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,9 @@ Or if you need to set multiple dimensions, you could use something like: Then you can get metrics for your `demo-web-puma` app. List of metrics: +* busy_threads: "wholistic" stat reflecting the overall current state of work to be done and the capacity to do it. * pool_capacity: the number of requests that the server is capable of taking right now. -* max_threads: preconfigured maximum number of worker threads. +* max_threads: preconfigured maximum number of worker threads. * running: the number of running threads (spawned threads) for any Puma worker. * backlog: the number of connections in that worker's "todo" set waiting for a worker thread. diff --git a/lib/puma_cloudwatch/metrics/parser.rb b/lib/puma_cloudwatch/metrics/parser.rb index 9e67c86..bcd9ed1 100644 --- a/lib/puma_cloudwatch/metrics/parser.rb +++ b/lib/puma_cloudwatch/metrics/parser.rb @@ -1,6 +1,6 @@ class PumaCloudwatch::Metrics class Parser - METRICS = [:backlog, :running, :pool_capacity, :max_threads] + METRICS = [:backlog, :busy_threads, :running, :pool_capacity, :max_threads] def initialize(data) @data = data @@ -14,6 +14,7 @@ def call # Build this structure: # # [{:backlog=>[0, 0], + # :busy_threads=>[0, 0], # :running=>[0, 0], # :pool_capacity=>[16, 16], # :max_threads=>[16, 16]}] diff --git a/lib/puma_cloudwatch/metrics/sender.rb b/lib/puma_cloudwatch/metrics/sender.rb index c182c63..e77ea69 100644 --- a/lib/puma_cloudwatch/metrics/sender.rb +++ b/lib/puma_cloudwatch/metrics/sender.rb @@ -54,6 +54,7 @@ def call # # [{:backlog=>[0, 0], # :running=>[0, 0], + # :busy_threads=>[0, 0], # :pool_capacity=>[16, 16], # :max_threads=>[16, 16]}] # @@ -62,6 +63,9 @@ def call # [{:metric_name=>"backlog", # :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, # :storage_resolution=>60}, + # {:metric_name=>"busy_threads", + # :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, + # :storage_resolution=>60}, # {:metric_name=>"running", # :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, # :storage_resolution=>60}, diff --git a/spec/puma_cloudwatch/metrics/parser_spec.rb b/spec/puma_cloudwatch/metrics/parser_spec.rb index 3407279..2bb2a88 100644 --- a/spec/puma_cloudwatch/metrics/parser_spec.rb +++ b/spec/puma_cloudwatch/metrics/parser_spec.rb @@ -5,6 +5,7 @@ let(:data) do {"started_at"=>"2019-09-16T19:20:12Z", "backlog"=>0, + "busy_threads"=>0, "running"=>16, "pool_capacity"=>8, "max_threads"=>16} @@ -15,6 +16,7 @@ expect(results).to be_a(Array) expect(results).to eq( [{:backlog=>[0], + :busy_threads=>[0], :running=>[16], :pool_capacity=>[8], :max_threads=>[16]}] @@ -69,7 +71,7 @@ "booted"=>true, "last_checkin"=>"2019-09-16T16:12:41Z", "last_status"=> - {"backlog"=>0, "running"=>1, "pool_capacity"=>16, "max_threads"=>16}}, + {"backlog"=>0, "busy_threads"=>0, "running"=>1, "pool_capacity"=>16, "max_threads"=>16}}, {"started_at"=>"2019-09-16T16:12:11Z", "pid"=>19836, "index"=>1, @@ -78,6 +80,7 @@ "last_checkin"=>"2019-09-16T16:12:41Z", "last_status"=> {"backlog"=>0, + "busy_threads"=>0, "running"=>16, "pool_capacity"=>8, "max_threads"=>16}}]} @@ -89,6 +92,7 @@ expect(results).to be_a(Array) expect(results).to eq( [{:backlog=>[0, 0], + :busy_threads=>[0, 0], :running=>[1, 16], :pool_capacity=>[16, 8], :max_threads=>[16, 16]}] diff --git a/spec/puma_cloudwatch/metrics/sender_spec.rb b/spec/puma_cloudwatch/metrics/sender_spec.rb index 1566d56..9755cd2 100644 --- a/spec/puma_cloudwatch/metrics/sender_spec.rb +++ b/spec/puma_cloudwatch/metrics/sender_spec.rb @@ -5,6 +5,7 @@ context "metrics filled out" do let(:metrics) { [{:backlog=>[0], + :busy_threads=>[0], :running=>[16], :pool_capacity=>[8], :max_threads=>[16]}] @@ -17,6 +18,11 @@ :dimensions=>[{:name=>"App", :value=>"puma"}], :statistic_values=>{:sample_count=>1, :sum=>0, :minimum=>0, :maximum=>0}, :storage_resolution=>60 + }, + {:metric_name=>"busy_threads", + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>1, :sum=>0, :minimum=>0, :maximum=>0}, + :storage_resolution=>60 }, {:metric_name=>"running", :dimensions=>[{:name=>"App", :value=>"puma"}], @@ -48,6 +54,7 @@ context "metrics filled out" do let(:metrics) { [{:backlog=>[0, 0], + :busy_threads=>[0, 0], :running=>[0, 0], :pool_capacity=>[16, 16], :max_threads=>[16, 16]}] @@ -60,6 +67,11 @@ :dimensions=>[{:name=>"App", :value=>"puma"}], :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, :storage_resolution=>60 + }, + {:metric_name=>"busy_threads", + :dimensions=>[{:name=>"App", :value=>"puma"}], + :statistic_values=>{:sample_count=>2, :sum=>0, :minimum=>0, :maximum=>0}, + :storage_resolution=>60 }, {:metric_name=>"running", :dimensions=>[{:name=>"App", :value=>"puma"}],