-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gunicorn instrumentation via statsD and a new logger class #748
Conversation
Move setting of env vars from Arbiter.start to Arbiter.setup so that they are available during application start up when 'preload_app' is used. Closes #735
This looks like a pretty beautiful solution. I had forgotten how easy it is to send data to statsd. I wish we had this at my last company! |
Thanks @tilgovi |
A few questions:
|
|
Use extra keyword in logger, more pythonic capture response code as a rate metric
@tilgovi I've made the changes we discussed (using I have also added a test to verify that even if statsD instrumentation fails, the logger continues to work. |
def __init__(self, status): | ||
self.status = status | ||
|
||
def test_statsd_fail(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These don't actually assert anything, do they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine, I guess. I see you've wrapped all the methods in the logger in except handlers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, if the exception bubbles back up, which it should not, the test will fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! Right :)
On May 31, 2014 1:54 PM, "Alexis Lê-Quôc" notifications@github.com wrote:
In tests/test_009-statsd.py:
self.failp = failp
self.msgs = [] # accumulate messages for later inspection
- def send(self, msg):
if self.failp:
raise TestException("Should not interrupt the logger")
self.msgs.append(msg)
- def reset(self):
self.msgs = []
+class MockResponse(object):
- def init(self, status):
self.status = status
+def test_statsd_fail():
Right, if the exception bubbles back up, which it should not, the test
will fail.—
Reply to this email directly or view it on GitHub
https://github.com/benoitc/gunicorn/pull/748/files#r13263654.
@benoitc this looks alright to me. Thoughts? |
@benoitc any reason not to include this in the next release" |
The patch looks fine for me but I would change the way it is enabled before to integrate it. Instead of passing the class to the the logger class option and add an option to set the host I would automatically set the statd logger if the If it's done until tomorrow we can include it in R19.0. If not it will wait the next one (planned this month or in july). Thoughts? |
let's not wait much more for the 19,0, This feature will be added in 19.1 this month. We should put it in master ASAP. |
@benoitc I can implemented the suggested changes over the next week or so. |
@alq666 cool! will merge once everything is OK :) |
No need to specify a logger class. --statsd-to is enough to trigger the Statsd logger automatically
Looking great. The readme example needs to be updated to reflect the extras keyword use, yeah? |
@tilgovi should be good now. |
+1. Can we merge this branch? |
@@ -482,6 +482,11 @@ def manage_workers(self): | |||
(pid, _) = workers.pop(0) | |||
self.kill_worker(pid, signal.SIGTERM) | |||
|
|||
self.log.info("{0} workers".format(len(workers)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i can't test it right now but does this change works with the default logger?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does work with default logger indeed:
Jun 22 15:53:28 localhost gunicorn.test.app.error: [17090] Starting gunicorn 19.1.0
Jun 22 15:53:28 localhost gunicorn.test.app.error: [17090] Listening at: http://127.0.0.1:8000 (17090)
Jun 22 15:53:28 localhost gunicorn.test.app.error: [17090] Using worker: sync
Jun 22 15:53:28 localhost gunicorn.test.app.error: [17095] Booting worker with pid: 17095
Jun 22 15:53:29 localhost gunicorn.test.app.error: [17096] Booting worker with pid: 17096
Jun 22 15:53:29 localhost gunicorn.test.app.error: [17097] Booting worker with pid: 17097
Jun 22 15:53:29 localhost gunicorn.test.app.error: [17098] Booting worker with pid: 17098
Jun 22 15:53:29 localhost gunicorn.test.app.error: [17090] 4 workers
using gunicorn --log-syslog --log-level=info --workers=4 test:app
as a test.
gunicorn instrumentation via statsD and a new logger class
merged thanks! |
Really cool feature! I was wondering if there's a way to differentiate between multiple applications? Is there a way to assign a name/prefix to an instance of a gunicorn app to be reflected in the metric name? |
@srgshames good thought. |
I can certainly stick it in the middle in the normal case, just after In the case the statsd's implementation supports explicit tags (like
|
(This is another attempt at getting statsD instrumentation to gunicorn initially in #672)
What is this pull request?
statsd is the de facto low-overhead instrumentation of many web stacks. I have come across a number of different ways to instrument
gunicorn
, none of which are part of the core and rely on external scripts being run out-of-band to guess the number of requests processed or the amount of cpu spent.I am hereby proposing that gunicorn optionally submits metrics to a local (or remote) statsD instance with the use of
--logger-class gunicorn.instrument.statsd.Statsd
option. Being that statsD uses UDP as transport, the receiving end being up or down does not affect the performance of the gunicorn application (unlike other stat collection schemes).Here is an example of such metric being graphed.
How does this work?
The arbiter and the base worker use a new logger that can take additional arguments to turn a log message into a metric. In addition certain known logging levels are automatically turned into metrics.
In particular the
access
method is overriden to capture duration and count of each gunicorn request.The new logger class inherits from
gunicorn.glogging.Logger
so existing logging should be preserved. No external dependencies were created.Who is behind this?
I use gunicorn at Datadog and have found statsD an indispensable aid to measure the performance of high-traffic applications. There is no company-specific bits in the pull request of course.