mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
add syslog support.
Add options to setup logging to syslog: - `--log-syslog`: enable syslog. It default to `/var/run/syslog` on darwin, `/var/run/log` on freebsd, `/dev/log` on openbsd and udp://localhost:514 for other platforms. - `--log-syslog-prefix: Pass the parameter to use as the program name - `--log-syslog-to`: Setup the syslog address to send message. Address startinf by udp:// will send to udp, unix:// to a unix socket and tcp:// to tcp (useful for rsyslog) fix #452 .
This commit is contained in:
parent
ac1af72922
commit
dae4d38705
@ -33,7 +33,6 @@ class Application(object):
|
||||
self.load_config()
|
||||
except Exception as e:
|
||||
sys.stderr.write("\nError: %s\n" % str(e))
|
||||
traceback.print_exc()
|
||||
sys.stderr.flush()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ from gunicorn import six
|
||||
from gunicorn import util
|
||||
|
||||
KNOWN_SETTINGS = []
|
||||
PLATFORM = sys.platform
|
||||
|
||||
|
||||
def wrap_method(func):
|
||||
@ -70,9 +71,9 @@ class Config(object):
|
||||
"prog": self.prog
|
||||
}
|
||||
parser = argparse.ArgumentParser(**kwargs)
|
||||
parser.add_argument("args", nargs="*", help=argparse.SUPPRESS)
|
||||
|
||||
keys = list(self.settings)
|
||||
|
||||
def sorter(k):
|
||||
return (self.settings[k].section, self.settings[k].order)
|
||||
|
||||
@ -80,7 +81,8 @@ class Config(object):
|
||||
for k in keys:
|
||||
self.settings[k].add_option(parser)
|
||||
|
||||
parser.add_argument("args", nargs="*", help=argparse.SUPPRESS)
|
||||
|
||||
|
||||
return parser
|
||||
|
||||
@property
|
||||
@ -175,6 +177,10 @@ class Setting(object):
|
||||
default = None
|
||||
short = None
|
||||
desc = None
|
||||
nargs = None
|
||||
const = None
|
||||
|
||||
|
||||
|
||||
def __init__(self):
|
||||
if self.default is not None:
|
||||
@ -202,6 +208,12 @@ class Setting(object):
|
||||
if kwargs["action"] != "store":
|
||||
kwargs.pop("type")
|
||||
|
||||
if self.nargs is not None:
|
||||
kwargs["nargs"] = self.nargs
|
||||
|
||||
if self.const is not None:
|
||||
kwargs["const"] = self.const
|
||||
|
||||
parser.add_argument(*args, **kwargs)
|
||||
|
||||
def copy(self):
|
||||
@ -1217,3 +1229,48 @@ class CertFile(Setting):
|
||||
desc = """\
|
||||
SSL certificate file
|
||||
"""
|
||||
|
||||
|
||||
class SyslogTo(Setting):
|
||||
name = "syslog_addr"
|
||||
section = "Logging"
|
||||
cli = ["--log-syslog-to"]
|
||||
meta = "SYSLOG_ADDR"
|
||||
validator = validate_string
|
||||
|
||||
if PLATFORM == "darwin":
|
||||
default = "unix:///var/run/syslog"
|
||||
elif PLATFORM in ('freebsd', 'dragonfly', ):
|
||||
default = "unix:///var/run/log"
|
||||
elif PLATFORM == "openbsd":
|
||||
default = "unix:///dev/log"
|
||||
else:
|
||||
default = "udp://localhost:514"
|
||||
|
||||
desc = """\
|
||||
Address to send syslog messages
|
||||
"""
|
||||
|
||||
class Syslog(Setting):
|
||||
name = "syslog"
|
||||
section = "Logging"
|
||||
cli = ["--log-syslog"]
|
||||
validator = validate_bool
|
||||
action = 'store_true'
|
||||
default = False
|
||||
desc = """\
|
||||
Log to syslog.
|
||||
"""
|
||||
|
||||
|
||||
class SyslogPrefix(Setting):
|
||||
name = "syslog_prefix"
|
||||
section = "Logging"
|
||||
cli = ["--log-syslog-prefix"]
|
||||
meta = "SYSLOG_PREFIX"
|
||||
validator = validate_string
|
||||
default = None
|
||||
desc = """\
|
||||
makes gunicorn use the parameter as program-name in the
|
||||
syslog entry header.
|
||||
"""
|
||||
|
||||
@ -8,6 +8,7 @@ import logging
|
||||
logging.Logger.manager.emittedNoHandlerWarning = 1
|
||||
from logging.config import fileConfig
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
import threading
|
||||
@ -123,6 +124,41 @@ class SafeAtoms(dict):
|
||||
return '-'
|
||||
|
||||
|
||||
def parse_syslog_address(addr):
|
||||
|
||||
if addr.startswith("unix://"):
|
||||
return (socket.SOCK_STREAM, addr.split("unix://")[1])
|
||||
|
||||
if addr.startswith("udp://"):
|
||||
addr = addr.split("udp://")[1]
|
||||
socktype = socket.SOCK_DGRAM
|
||||
elif addr.startswith("tcp://"):
|
||||
addr = addr.split("tcp://")[1]
|
||||
socktype = socket.SOCK_STREAM
|
||||
else:
|
||||
raise RuntimeError("invalid syslog address")
|
||||
|
||||
if '[' in addr and ']' in addr:
|
||||
host = addr.split(']')[0][1:].lower()
|
||||
elif ':' in addr:
|
||||
host = addr.split(':')[0].lower()
|
||||
elif addr == "":
|
||||
host = "localhost"
|
||||
else:
|
||||
host = addr.lower()
|
||||
|
||||
addr = addr.split(']')[-1]
|
||||
if ":" in addr:
|
||||
port = addr.split(':', 1)[1]
|
||||
if not port.isdigit():
|
||||
raise RuntimeError("%r is not a valid port number." % port)
|
||||
port = int(port)
|
||||
else:
|
||||
port = 514
|
||||
|
||||
return (socktype, (host, port))
|
||||
|
||||
|
||||
class Logger(object):
|
||||
|
||||
LOG_LEVELS = {
|
||||
@ -137,10 +173,12 @@ class Logger(object):
|
||||
datefmt = r"%Y-%m-%d %H:%M:%S"
|
||||
|
||||
access_fmt = "%(message)s"
|
||||
syslog_fmt = "[%(process)d] %(message)s"
|
||||
|
||||
def __init__(self, cfg):
|
||||
self.error_log = logging.getLogger("gunicorn.error")
|
||||
self.access_log = logging.getLogger("gunicorn.access")
|
||||
|
||||
self.error_handlers = []
|
||||
self.access_handlers = []
|
||||
self.cfg = cfg
|
||||
@ -165,6 +203,11 @@ class Logger(object):
|
||||
if cfg.accesslog is not None:
|
||||
self._set_handler(self.access_log, cfg.accesslog,
|
||||
fmt=logging.Formatter(self.access_fmt))
|
||||
|
||||
|
||||
if cfg.syslog:
|
||||
self._set_syslog_handler(self.error_log, cfg, self.syslog_fmt)
|
||||
|
||||
else:
|
||||
if os.path.exists(cfg.logconfig):
|
||||
fileConfig(cfg.logconfig, defaults=CONFIG_DEFAULTS,
|
||||
@ -296,3 +339,19 @@ class Logger(object):
|
||||
h.setFormatter(fmt)
|
||||
h._gunicorn = True
|
||||
log.addHandler(h)
|
||||
|
||||
def _set_syslog_handler(self, log, cfg, fmt):
|
||||
# setup format
|
||||
if not cfg.syslog_prefix:
|
||||
prefix = cfg.proc_name.replace(":", ".")
|
||||
prefix = "gunicorn.%s" % prefix
|
||||
fmt = logging.Formatter(r"%s: %s" % (prefix, fmt))
|
||||
|
||||
# parse syslog address
|
||||
socktype, addr = parse_syslog_address(cfg.syslog_addr)
|
||||
|
||||
# finally setup the syslog handler
|
||||
h = logging.handlers.SysLogHandler(address=addr, socktype=socktype)
|
||||
h.setFormatter(fmt)
|
||||
h._gunicorn = True
|
||||
log.addHandler(h)
|
||||
|
||||
@ -224,6 +224,13 @@ def parse_address(netloc, default_port=8000):
|
||||
if netloc.startswith("unix:"):
|
||||
return netloc.split("unix:")[1]
|
||||
|
||||
if netloc.startswith("unix://"):
|
||||
return netloc.split("unix://")[1]
|
||||
|
||||
if netloc.startswith("tcp://"):
|
||||
netloc = netloc.split("tcp://")[1]
|
||||
|
||||
|
||||
# get host
|
||||
if '[' in netloc and ']' in netloc:
|
||||
host = netloc.split(']')[0][1:].lower()
|
||||
@ -245,7 +252,6 @@ def parse_address(netloc, default_port=8000):
|
||||
port = default_port
|
||||
return (host, port)
|
||||
|
||||
|
||||
def get_maxfd():
|
||||
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
||||
if (maxfd == resource.RLIM_INFINITY):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user