{"id":20657773,"url":"https://github.com/boltops-tools/puma-cloudwatch","last_synced_at":"2025-04-19T13:18:47.889Z","repository":{"id":46181889,"uuid":"208908584","full_name":"boltops-tools/puma-cloudwatch","owner":"boltops-tools","description":"Puma plugin sends puma metrics to CloudWatch","archived":false,"fork":false,"pushed_at":"2024-03-02T15:49:52.000Z","size":70,"stargazers_count":20,"open_issues_count":2,"forks_count":12,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-01T11:29:03.893Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boltops-tools.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-16T22:22:13.000Z","updated_at":"2023-11-21T13:19:20.000Z","dependencies_parsed_at":"2023-02-03T04:00:15.255Z","dependency_job_id":null,"html_url":"https://github.com/boltops-tools/puma-cloudwatch","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boltops-tools%2Fpuma-cloudwatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boltops-tools%2Fpuma-cloudwatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boltops-tools%2Fpuma-cloudwatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boltops-tools%2Fpuma-cloudwatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boltops-tools","download_url":"https://codeload.github.com/boltops-tools/puma-cloudwatch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224954293,"owners_count":17397843,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T18:23:05.140Z","updated_at":"2024-11-16T18:23:05.826Z","avatar_url":"https://github.com/boltops-tools.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Puma Cloudwatch Plugin\n\n[![Gem Version](https://badge.fury.io/rb/puma-cloudwatch.svg)](https://badge.fury.io/rb/puma-cloudwatch)\n\n[![BoltOps Badge](https://img.boltops.com/boltops/badges/boltops-badge.png)](https://www.boltops.com)\n\nA [puma](https://puma.io) plugin that sends puma stats to CloudWatch.\n\n## Usage\n\n**Important**: To enable the plugin to send metrics to CloudWatch you must set the `PUMA_CLOUDWATCH_ENABLED` env variable. This allows you to send only metrics on configured servers and not unintentionally send them locally.\n\nIt also strongly encourage to set the `PUMA_CLOUDWATCH_DIMENSION_VALUE` env variable to include your application name. For example, if your application is named \"demo-web\", this would be a good value to use:\n\n    PUMA_CLOUDWATCH_DIMENSION_VALUE=demo-web-puma\n\nOr if you need to set multiple dimensions, you could use something like:\n\n    PUMA_CLOUDWATCH_DIMENSIONS=\"Service=web,Cluster=primary,Environment=production\"\n\nThen you can get metrics for your `demo-web-puma` app. List of metrics:\n\n* pool_capacity: the number of requests that the server is capable of taking right now.\n* max_threads:  preconfigured maximum number of worker threads.\n* running: the number of running threads (spawned threads) for any Puma worker.\n* backlog: the number of connections in that worker's \"todo\" set waiting for a worker thread.\n\nThe `pool_capacity` metric is important. It can be used to show how busy the server is getting before it reaches capacity.  The formula is:\n\n    busy_percent = ( 1 - pool_capacity / max_threads ) * 100\n\n### Environment Variables\n\nThe plugin's settings can be controlled with environmental variables:\n\nEnv Var | Description | Default Value\n--- | --- | ---\nPUMA\\_CLOUDWATCH\\_DEBUG | When set, the plugin prints out the metrics that get sent to CloudWatch. | (unset)\nPUMA\\_CLOUDWATCH\\_DIMENSION\\_NAME | CloudWatch metric dimension name | App\nPUMA\\_CLOUDWATCH\\_DIMENSION\\_VALUE | CloudWatch metric dimension value | puma\nPUMA\\_CLOUDWATCH\\_DIMENSIONS | CloudWatch metric dimensions | (unset)\nPUMA\\_CLOUDWATCH\\_ENABLED | Enables sending of the data to CloudWatch. | (unset)\nPUMA\\_CLOUDWATCH\\_FREQUENCY | How often to send data to CloudWatch in seconds. | 60\nPUMA\\_CLOUDWATCH\\_NAMESPACE | CloudWatch metric namespace | WebServer\nPUMA\\_CLOUDWATCH\\_AWS\\_REGION | CloudWatch metric AWS region | (unset)\nPUMA\\_CLOUDWATCH\\_AWS\\_ACCESS_KEY_ID | AWS access key ID | (unset)\nPUMA\\_CLOUDWATCH\\_AWS\\_SECRET_ACCESS_KEY | AWS secret access key | (unset)\nPUMA\\_CLOUDWATCH\\_MUTE\\_START\\_MESSAGE | Mutes the \"puma-cloudwatch plugin\" startup message | (unset)\n\n### Sum and Frequency Normalization\n\nIf you leave the `PUMA_CLOUDWATCH_FREQUENCY` at its default of 60 seconds and graph out the `pool_capacity` capacity with a 1-minute period resolution, then the CloudWatch Sum statistic is \"normalized\" and useful. It shows the overall capacity total of the `demo-web-puma` servers.  Particularly, the `pool_capacity` shows available capacity,  and  `pool_threads` shows the total threads configured.\n\nIf you change the CloudWatch send frequency, then Sum statistic must be normalized by changing the period on the chart.  For example, let's say you use `PUMA_CLOUDWATCH_FREQUENCY=30`. Then puma-cloudwatch will send data every 30s. However, if the chart is still using a 1-minute period, then the Sum statistic would \"double\".  Capacity has not doubled, puma-cloudwatch is just sending twice as much data for that period.  To normalize the Sum, set the time period resolution to match the frequency. In this case: 30 seconds.\n\nIf you use the Average statistic, then you don't have to worry about normalizing. Average is inherently normalized.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'puma-cloudwatch'\n```\n\nAnd then execute:\n\n    $ bundle\n\nAdd these 2 lines your `config/puma.rb`:\n\nconfig/puma.rb\n\n```ruby\nactivate_control_app\nplugin :cloudwatch\n```\n\nIt activates the puma control rack application, and enables the puma-cloudwatch plugin to send metrics.\n\n### More Setup Notes\n\nMake sure that EC2 instance running the puma server has IAM permission to publish to CloudWatch. If you are using ECS, the default permissions for the ECS task should work.\n\nAlternatively, you may configure an AWS Access Key ID and Secret Key with the `PUMA_CLOUDWATCH_AWS_ACCESS_KEY_ID` and `PUMA_CLOUDWATCH_AWS_SECRET_ACCESS_KEY` env variables.\n\nIf are you using ECS awsvpc, make sure you have the task running on private subnets with a NAT. From the AWS docs: [Task Networking with the awsvpc Network Mode](https://docs.aws.amazon.com/en_pv/AmazonECS/latest/developerguide/task-networking.html)\n\n\u003e The awsvpc network mode does not provide task ENIs with public IP addresses for tasks that use the EC2 launch type. To access the internet, tasks that use the EC2 launch type must be launched in a private subnet that is configured to use a NAT gateway.\n\n## How It Works: Internal Puma Stats Server\n\nPuma has an internal server that has a stats endpoint. It runs on a unix socket by default. The puma-cloudwatch works by running continuous loop that polls this puma socket.\n\n### Debug Internal Puma Server: Socket\n\nBy default, the socket file is a random path and token. You can use `PUMA_CLOUDWATCH_DEBUG` to see the puma `control_url` and `control_auth_token`.\n\nYou'll see something like this:\n\n    $ PUMA_CLOUDWATCH_DEBUG=1 rail server\n    * Starting control server on unix:///tmp/puma-status-1689096041362-18083\n    Use Ctrl-C to stop\n    puma control_url unix:///tmp/puma-status-1689096041362-18083\n    puma control_auth_token 609a3fe77de470ad87eaaf0a28a4d22d\n\nTo test the socket\n\n    echo -e \"GET /stats?token=62a21462ce921590337cfe8a2bf53505 HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\"  | socat - UNIX-CONNECT:/tmp/puma-status-1689095966545-17509\n\nYou can specify the path and disable the token to make it easier:\n\nconfig/puma.rb\n\n```ruby\nactivate_control_app \"unix://tmp/pumactl.sock\", { no_token: true }\n# another example with full path, note the additinal beginning /\n# activate_control_app \"unix:///full/path/tmp/pumactl.sock\", { no_token: true }\nplugin :cloudwatch\n```\n\nSend a stats request to the socket with `socat`\n\n    $ echo -e \"GET /stats HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\"  | socat - UNIX-CONNECT:tmp/pumactl.sock\n    HTTP/1.1 200 OK\n    Content-Type: application/json\n    Connection: close\n    Content-Length: 114\n\n    {\"started_at\":\"2023-07-11T16:32:37Z\",\"backlog\":0,\"running\":5,\"pool_capacity\":5,\"max_threads\":5,\"requests_count\":0}\n\n### Debug Internal Puma Server: TCP Port\n\nYou can also use a tcp port instead.\n\nconfig/puma.rb\n\n```ruby\nactivate_control_app \"tcp://127.0.0.1:9293\", { no_token: true }\nplugin :cloudwatch\n```\n\nYou can see the stats with `curl`.\n\n    $ curl \"localhost:9293/stats\"\n    {\"started_at\":\"2023-07-11T17:17:31Z\",\"backlog\":0,\"running\":5,\"pool_capacity\":5,\"max_threads\":5,\"requests_count\":0}\n\n### puma control-url option note\n\nIf you're calling puma directly, there's an option to specify the control url and token, example:\n\n    $ puma --control-url tcp://127.0.0.1:9293 --control-token foo\n    * Listening on http://0.0.0.0:3000\n    * Starting control server on http://127.0.0.1:9293\n\nThis conflicts with activate the control app in the puma.rb\n\nconfig/puma.rb\n\n```ruby\nactivate_control_app\nplugin :cloudwatch\n```\n\nSo do not use those options when using this puma plugin.\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/boltops-tools/puma-cloudwatch\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboltops-tools%2Fpuma-cloudwatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboltops-tools%2Fpuma-cloudwatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboltops-tools%2Fpuma-cloudwatch/lists"}