mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Merge pull request #1010 from krallin/fix-statsd-py3
Fix statsd Logging in Python 3
This commit is contained in:
commit
a7354cf8fe
@ -224,8 +224,8 @@ class Logger(object):
|
|||||||
def debug(self, msg, *args, **kwargs):
|
def debug(self, msg, *args, **kwargs):
|
||||||
self.error_log.debug(msg, *args, **kwargs)
|
self.error_log.debug(msg, *args, **kwargs)
|
||||||
|
|
||||||
def exception(self, msg, *args):
|
def exception(self, msg, *args, **kwargs):
|
||||||
self.error_log.exception(msg, *args)
|
self.error_log.exception(msg, *args, **kwargs)
|
||||||
|
|
||||||
def log(self, lvl, msg, *args, **kwargs):
|
def log(self, lvl, msg, *args, **kwargs):
|
||||||
if isinstance(lvl, string_types):
|
if isinstance(lvl, string_types):
|
||||||
|
|||||||
@ -8,7 +8,9 @@
|
|||||||
import socket
|
import socket
|
||||||
import logging
|
import logging
|
||||||
from re import sub
|
from re import sub
|
||||||
|
|
||||||
from gunicorn.glogging import Logger
|
from gunicorn.glogging import Logger
|
||||||
|
from gunicorn import six
|
||||||
|
|
||||||
# Instrumentation constants
|
# Instrumentation constants
|
||||||
STATSD_DEFAULT_PORT = 8125
|
STATSD_DEFAULT_PORT = 8125
|
||||||
@ -82,7 +84,7 @@ class Statsd(Logger):
|
|||||||
if msg is not None and len(msg) > 0:
|
if msg is not None and len(msg) > 0:
|
||||||
Logger.log(self, lvl, msg, *args, **kwargs)
|
Logger.log(self, lvl, msg, *args, **kwargs)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
Logger.warning(self, "Failed to log to statsd", exc_info=True)
|
||||||
|
|
||||||
# access logging
|
# access logging
|
||||||
def access(self, resp, req, environ, request_time):
|
def access(self, resp, req, environ, request_time):
|
||||||
@ -98,29 +100,22 @@ class Statsd(Logger):
|
|||||||
# statsD methods
|
# statsD methods
|
||||||
# you can use those directly if you want
|
# you can use those directly if you want
|
||||||
def gauge(self, name, value):
|
def gauge(self, name, value):
|
||||||
try:
|
self._sock_send("{0}{1}:{2}|g".format(self.prefix, name, value))
|
||||||
if self.sock:
|
|
||||||
self.sock.send("{0}{1}:{2}|g".format(self.prefix, name, value))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def increment(self, name, value, sampling_rate=1.0):
|
def increment(self, name, value, sampling_rate=1.0):
|
||||||
try:
|
self._sock_send("{0}{1}:{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
||||||
if self.sock:
|
|
||||||
self.sock.send("{0}{1}:{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def decrement(self, name, value, sampling_rate=1.0):
|
def decrement(self, name, value, sampling_rate=1.0):
|
||||||
try:
|
self._sock_send("{0){1}:-{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
||||||
if self.sock:
|
|
||||||
self.sock.send("{0){1}:-{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def histogram(self, name, value):
|
def histogram(self, name, value):
|
||||||
|
self._sock_send("{0}{1}:{2}|ms".format(self.prefix, name, value))
|
||||||
|
|
||||||
|
def _sock_send(self, msg):
|
||||||
try:
|
try:
|
||||||
|
if isinstance(msg, six.text_type):
|
||||||
|
msg = msg.encode("ascii")
|
||||||
if self.sock:
|
if self.sock:
|
||||||
self.sock.send("{0}{1}:{2}|ms".format(self.prefix, name, value))
|
self.sock.send(msg)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
Logger.warning(self, "Error sending message to statsd", exc_info=True)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
import socket
|
||||||
|
|
||||||
import t
|
import t
|
||||||
|
|
||||||
@ -8,12 +9,18 @@ except ImportError:
|
|||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
|
||||||
from gunicorn.config import Config
|
from gunicorn.config import Config
|
||||||
from gunicorn.instrument.statsd import Statsd
|
from gunicorn.instrument.statsd import Statsd
|
||||||
|
|
||||||
|
|
||||||
class TestException(Exception): pass
|
|
||||||
|
|
||||||
|
class TestException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class MockSocket(object):
|
class MockSocket(object):
|
||||||
"Pretend to be a UDP socket"
|
"Pretend to be a UDP socket"
|
||||||
@ -24,7 +31,25 @@ class MockSocket(object):
|
|||||||
def send(self, msg):
|
def send(self, msg):
|
||||||
if self.failp:
|
if self.failp:
|
||||||
raise TestException("Should not interrupt the logger")
|
raise TestException("Should not interrupt the logger")
|
||||||
self.msgs.append(msg)
|
|
||||||
|
sock_dir = tempfile.mkdtemp()
|
||||||
|
sock_file = os.path.join(sock_dir, "test.sock")
|
||||||
|
|
||||||
|
server = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
|
||||||
|
client = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
|
||||||
|
|
||||||
|
try:
|
||||||
|
server.bind(sock_file)
|
||||||
|
client.connect(sock_file)
|
||||||
|
|
||||||
|
client.send(msg)
|
||||||
|
self.msgs.append(server.recv(1024))
|
||||||
|
|
||||||
|
finally:
|
||||||
|
client.close()
|
||||||
|
server.close()
|
||||||
|
shutil.rmtree(sock_dir)
|
||||||
|
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.msgs = []
|
self.msgs = []
|
||||||
@ -53,30 +78,30 @@ def test_instrument():
|
|||||||
|
|
||||||
# Regular message
|
# Regular message
|
||||||
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
||||||
t.eq(logger.sock.msgs[0], "gunicorn.test:666|g")
|
t.eq(logger.sock.msgs[0], b"gunicorn.test:666|g")
|
||||||
t.eq(sio.getvalue(), "Blah\n")
|
t.eq(sio.getvalue(), "Blah\n")
|
||||||
logger.sock.reset()
|
logger.sock.reset()
|
||||||
|
|
||||||
# Only metrics, no logging
|
# Only metrics, no logging
|
||||||
logger.info("", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
logger.info("", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
||||||
t.eq(logger.sock.msgs[0], "gunicorn.test:666|g")
|
t.eq(logger.sock.msgs[0], b"gunicorn.test:666|g")
|
||||||
t.eq(sio.getvalue(), "Blah\n") # log is unchanged
|
t.eq(sio.getvalue(), "Blah\n") # log is unchanged
|
||||||
logger.sock.reset()
|
logger.sock.reset()
|
||||||
|
|
||||||
# Debug logging also supports metrics
|
# Debug logging also supports metrics
|
||||||
logger.debug("", extra={"mtype": "gauge", "metric": "gunicorn.debug", "value": 667})
|
logger.debug("", extra={"mtype": "gauge", "metric": "gunicorn.debug", "value": 667})
|
||||||
t.eq(logger.sock.msgs[0], "gunicorn.debug:667|g")
|
t.eq(logger.sock.msgs[0], b"gunicorn.debug:667|g")
|
||||||
t.eq(sio.getvalue(), "Blah\n") # log is unchanged
|
t.eq(sio.getvalue(), "Blah\n") # log is unchanged
|
||||||
logger.sock.reset()
|
logger.sock.reset()
|
||||||
|
|
||||||
logger.critical("Boom")
|
logger.critical("Boom")
|
||||||
t.eq(logger.sock.msgs[0], "gunicorn.log.critical:1|c|@1.0")
|
t.eq(logger.sock.msgs[0], b"gunicorn.log.critical:1|c|@1.0")
|
||||||
logger.sock.reset()
|
logger.sock.reset()
|
||||||
|
|
||||||
logger.access(MockResponse("200 OK"), None, {}, timedelta(seconds=7))
|
logger.access(MockResponse("200 OK"), None, {}, timedelta(seconds=7))
|
||||||
t.eq(logger.sock.msgs[0], "gunicorn.request.duration:7000.0|ms")
|
t.eq(logger.sock.msgs[0], b"gunicorn.request.duration:7000.0|ms")
|
||||||
t.eq(logger.sock.msgs[1], "gunicorn.requests:1|c|@1.0")
|
t.eq(logger.sock.msgs[1], b"gunicorn.requests:1|c|@1.0")
|
||||||
t.eq(logger.sock.msgs[2], "gunicorn.request.status.200:1|c|@1.0")
|
t.eq(logger.sock.msgs[2], b"gunicorn.request.status.200:1|c|@1.0")
|
||||||
|
|
||||||
def test_prefix():
|
def test_prefix():
|
||||||
c = Config()
|
c = Config()
|
||||||
@ -85,7 +110,7 @@ def test_prefix():
|
|||||||
logger.sock = MockSocket(False)
|
logger.sock = MockSocket(False)
|
||||||
|
|
||||||
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
||||||
t.eq(logger.sock.msgs[0], "test.gunicorn.test:666|g")
|
t.eq(logger.sock.msgs[0], b"test.gunicorn.test:666|g")
|
||||||
|
|
||||||
def test_prefix_no_dot():
|
def test_prefix_no_dot():
|
||||||
c = Config()
|
c = Config()
|
||||||
@ -94,7 +119,7 @@ def test_prefix_no_dot():
|
|||||||
logger.sock = MockSocket(False)
|
logger.sock = MockSocket(False)
|
||||||
|
|
||||||
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
||||||
t.eq(logger.sock.msgs[0], "test.gunicorn.test:666|g")
|
t.eq(logger.sock.msgs[0], b"test.gunicorn.test:666|g")
|
||||||
|
|
||||||
def test_prefix_multiple_dots():
|
def test_prefix_multiple_dots():
|
||||||
c = Config()
|
c = Config()
|
||||||
@ -103,7 +128,7 @@ def test_prefix_multiple_dots():
|
|||||||
logger.sock = MockSocket(False)
|
logger.sock = MockSocket(False)
|
||||||
|
|
||||||
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
||||||
t.eq(logger.sock.msgs[0], "test.gunicorn.test:666|g")
|
t.eq(logger.sock.msgs[0], b"test.gunicorn.test:666|g")
|
||||||
|
|
||||||
def test_prefix_nested():
|
def test_prefix_nested():
|
||||||
c = Config()
|
c = Config()
|
||||||
@ -112,4 +137,4 @@ def test_prefix_nested():
|
|||||||
logger.sock = MockSocket(False)
|
logger.sock = MockSocket(False)
|
||||||
|
|
||||||
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666})
|
||||||
t.eq(logger.sock.msgs[0], "test.asdf.gunicorn.test:666|g")
|
t.eq(logger.sock.msgs[0], b"test.asdf.gunicorn.test:666|g")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user