From 5803f835f6fbf8c166af99cba1617cb0d3863210 Mon Sep 17 00:00:00 2001 From: Wojciech Malinowski Date: Thu, 6 Jun 2019 15:13:23 +0200 Subject: [PATCH] Added a possibility of logging the metrics to a Unix domain socket instead of UDP --- docs/source/settings.rst | 11 +++++++++++ gunicorn/config.py | 16 +++++++++++++++- gunicorn/instrument/statsd.py | 14 +++++++++++--- tests/test_config.py | 9 ++++++++- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/docs/source/settings.rst b/docs/source/settings.rst index 16d8961a..e759ded7 100644 --- a/docs/source/settings.rst +++ b/docs/source/settings.rst @@ -363,6 +363,17 @@ statsd_host .. versionadded:: 19.1 +.. _statsd-socket: + +statsd_socket +~~~~~~~~~~~~~ + +* ``--statsd-socket STATSD_SOCKET`` +* ``None`` + +Unix domain socket of the statsd server to log to. +Supersedes ``statsd_host`` if provided. + .. _dogstatsd-tags: dogstatsd_tags diff --git a/gunicorn/config.py b/gunicorn/config.py index e8e0f926..3f48b6dd 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -144,7 +144,9 @@ class Config(object): # if default logger is in use, and statsd is on, automagically switch # to the statsd logger if uri == LoggerClass.default: - if 'statsd_host' in self.settings and self.settings['statsd_host'].value is not None: + statsd_address = 'statsd_socket' in self.settings and self.settings['statsd_socket'].value or \ + 'statsd_host' in self.settings and self.settings['statsd_host'].value + if statsd_address is not None: uri = "gunicorn.instrument.statsd.Statsd" logger_class = util.load_class( @@ -1478,6 +1480,18 @@ class StatsdHost(Setting): .. versionadded:: 19.1 """ +class StatsdSocket(Setting): + name = "statsd_socket" + section = "Logging" + cli = ["--statsd-socket"] + meta = "STATSD_SOCKET" + default = None + validator = validate_string + desc = """\ + Unix domain socket of the statsd server to log to. + Supersedes ``statsd_host`` if provided. + """ + # Datadog Statsd (dogstatsd) tags. https://docs.datadoghq.com/developers/dogstatsd/ class DogstatsdTags(Setting): name = "dogstatsd_tags" diff --git a/gunicorn/instrument/statsd.py b/gunicorn/instrument/statsd.py index 9a537205..ee6d5308 100644 --- a/gunicorn/instrument/statsd.py +++ b/gunicorn/instrument/statsd.py @@ -27,10 +27,18 @@ class Statsd(Logger): """ Logger.__init__(self, cfg) self.prefix = sub(r"^(.+[^.]+)\.*$", "\\g<1>.", cfg.statsd_prefix) - try: + + if cfg.statsd_socket: + address_family = socket.AF_UNIX + address = cfg.statsd_socket + elif cfg.statsd_host: + address_family = socket.AF_INET host, port = cfg.statsd_host - self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.sock.connect((host, int(port))) + address = (host, int(port)) + + try: + self.sock = socket.socket(address_family, socket.SOCK_DGRAM) + self.sock.connect(address) except Exception: self.sock = None diff --git a/tests/test_config.py b/tests/test_config.py index 0587c63c..db108b9b 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -306,13 +306,20 @@ def test_nworkers_changed(): assert c.nworkers_changed(1, 2, 3) == 3 -def test_statsd_changes_logger(): +def test_statsd_host_changes_logger(): c = config.Config() assert c.logger_class == glogging.Logger c.set('statsd_host', 'localhost:12345') assert c.logger_class == statsd.Statsd +def test_statsd_socket_changes_logger(): + c = config.Config() + assert c.logger_class == glogging.Logger + c.set('statsd_socket', '/var/run/sock') + assert c.logger_class == statsd.Statsd + + class MyLogger(glogging.Logger): # dummy custom logger class for testing pass