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()
|
self.load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.stderr.write("\nError: %s\n" % str(e))
|
sys.stderr.write("\nError: %s\n" % str(e))
|
||||||
traceback.print_exc()
|
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@ from gunicorn import six
|
|||||||
from gunicorn import util
|
from gunicorn import util
|
||||||
|
|
||||||
KNOWN_SETTINGS = []
|
KNOWN_SETTINGS = []
|
||||||
|
PLATFORM = sys.platform
|
||||||
|
|
||||||
|
|
||||||
def wrap_method(func):
|
def wrap_method(func):
|
||||||
@ -70,9 +71,9 @@ class Config(object):
|
|||||||
"prog": self.prog
|
"prog": self.prog
|
||||||
}
|
}
|
||||||
parser = argparse.ArgumentParser(**kwargs)
|
parser = argparse.ArgumentParser(**kwargs)
|
||||||
|
parser.add_argument("args", nargs="*", help=argparse.SUPPRESS)
|
||||||
|
|
||||||
keys = list(self.settings)
|
keys = list(self.settings)
|
||||||
|
|
||||||
def sorter(k):
|
def sorter(k):
|
||||||
return (self.settings[k].section, self.settings[k].order)
|
return (self.settings[k].section, self.settings[k].order)
|
||||||
|
|
||||||
@ -80,7 +81,8 @@ class Config(object):
|
|||||||
for k in keys:
|
for k in keys:
|
||||||
self.settings[k].add_option(parser)
|
self.settings[k].add_option(parser)
|
||||||
|
|
||||||
parser.add_argument("args", nargs="*", help=argparse.SUPPRESS)
|
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -175,6 +177,10 @@ class Setting(object):
|
|||||||
default = None
|
default = None
|
||||||
short = None
|
short = None
|
||||||
desc = None
|
desc = None
|
||||||
|
nargs = None
|
||||||
|
const = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
if self.default is not None:
|
if self.default is not None:
|
||||||
@ -202,6 +208,12 @@ class Setting(object):
|
|||||||
if kwargs["action"] != "store":
|
if kwargs["action"] != "store":
|
||||||
kwargs.pop("type")
|
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)
|
parser.add_argument(*args, **kwargs)
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
@ -1217,3 +1229,48 @@ class CertFile(Setting):
|
|||||||
desc = """\
|
desc = """\
|
||||||
SSL certificate file
|
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
|
logging.Logger.manager.emittedNoHandlerWarning = 1
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
import os
|
import os
|
||||||
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import threading
|
import threading
|
||||||
@ -123,6 +124,41 @@ class SafeAtoms(dict):
|
|||||||
return '-'
|
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):
|
class Logger(object):
|
||||||
|
|
||||||
LOG_LEVELS = {
|
LOG_LEVELS = {
|
||||||
@ -137,10 +173,12 @@ class Logger(object):
|
|||||||
datefmt = r"%Y-%m-%d %H:%M:%S"
|
datefmt = r"%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
access_fmt = "%(message)s"
|
access_fmt = "%(message)s"
|
||||||
|
syslog_fmt = "[%(process)d] %(message)s"
|
||||||
|
|
||||||
def __init__(self, cfg):
|
def __init__(self, cfg):
|
||||||
self.error_log = logging.getLogger("gunicorn.error")
|
self.error_log = logging.getLogger("gunicorn.error")
|
||||||
self.access_log = logging.getLogger("gunicorn.access")
|
self.access_log = logging.getLogger("gunicorn.access")
|
||||||
|
|
||||||
self.error_handlers = []
|
self.error_handlers = []
|
||||||
self.access_handlers = []
|
self.access_handlers = []
|
||||||
self.cfg = cfg
|
self.cfg = cfg
|
||||||
@ -165,6 +203,11 @@ class Logger(object):
|
|||||||
if cfg.accesslog is not None:
|
if cfg.accesslog is not None:
|
||||||
self._set_handler(self.access_log, cfg.accesslog,
|
self._set_handler(self.access_log, cfg.accesslog,
|
||||||
fmt=logging.Formatter(self.access_fmt))
|
fmt=logging.Formatter(self.access_fmt))
|
||||||
|
|
||||||
|
|
||||||
|
if cfg.syslog:
|
||||||
|
self._set_syslog_handler(self.error_log, cfg, self.syslog_fmt)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if os.path.exists(cfg.logconfig):
|
if os.path.exists(cfg.logconfig):
|
||||||
fileConfig(cfg.logconfig, defaults=CONFIG_DEFAULTS,
|
fileConfig(cfg.logconfig, defaults=CONFIG_DEFAULTS,
|
||||||
@ -296,3 +339,19 @@ class Logger(object):
|
|||||||
h.setFormatter(fmt)
|
h.setFormatter(fmt)
|
||||||
h._gunicorn = True
|
h._gunicorn = True
|
||||||
log.addHandler(h)
|
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:"):
|
if netloc.startswith("unix:"):
|
||||||
return netloc.split("unix:")[1]
|
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
|
# get host
|
||||||
if '[' in netloc and ']' in netloc:
|
if '[' in netloc and ']' in netloc:
|
||||||
host = netloc.split(']')[0][1:].lower()
|
host = netloc.split(']')[0][1:].lower()
|
||||||
@ -245,7 +252,6 @@ def parse_address(netloc, default_port=8000):
|
|||||||
port = default_port
|
port = default_port
|
||||||
return (host, port)
|
return (host, port)
|
||||||
|
|
||||||
|
|
||||||
def get_maxfd():
|
def get_maxfd():
|
||||||
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
||||||
if (maxfd == resource.RLIM_INFINITY):
|
if (maxfd == resource.RLIM_INFINITY):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user