aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/gunicorn/glogging.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/gunicorn/glogging.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/gunicorn/glogging.py')
-rw-r--r--.venv/lib/python3.12/site-packages/gunicorn/glogging.py474
1 files changed, 474 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/gunicorn/glogging.py b/.venv/lib/python3.12/site-packages/gunicorn/glogging.py
new file mode 100644
index 00000000..b552e26a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/gunicorn/glogging.py
@@ -0,0 +1,474 @@
+# -*- coding: utf-8 -
+#
+# This file is part of gunicorn released under the MIT license.
+# See the NOTICE for more information.
+
+import base64
+import binascii
+import json
+import time
+import logging
+logging.Logger.manager.emittedNoHandlerWarning = 1 # noqa
+from logging.config import dictConfig
+from logging.config import fileConfig
+import os
+import socket
+import sys
+import threading
+import traceback
+
+from gunicorn import util
+
+
+# syslog facility codes
+SYSLOG_FACILITIES = {
+ "auth": 4,
+ "authpriv": 10,
+ "cron": 9,
+ "daemon": 3,
+ "ftp": 11,
+ "kern": 0,
+ "lpr": 6,
+ "mail": 2,
+ "news": 7,
+ "security": 4, # DEPRECATED
+ "syslog": 5,
+ "user": 1,
+ "uucp": 8,
+ "local0": 16,
+ "local1": 17,
+ "local2": 18,
+ "local3": 19,
+ "local4": 20,
+ "local5": 21,
+ "local6": 22,
+ "local7": 23
+}
+
+CONFIG_DEFAULTS = {
+ "version": 1,
+ "disable_existing_loggers": False,
+ "root": {"level": "INFO", "handlers": ["console"]},
+ "loggers": {
+ "gunicorn.error": {
+ "level": "INFO",
+ "handlers": ["error_console"],
+ "propagate": True,
+ "qualname": "gunicorn.error"
+ },
+
+ "gunicorn.access": {
+ "level": "INFO",
+ "handlers": ["console"],
+ "propagate": True,
+ "qualname": "gunicorn.access"
+ }
+ },
+ "handlers": {
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "generic",
+ "stream": "ext://sys.stdout"
+ },
+ "error_console": {
+ "class": "logging.StreamHandler",
+ "formatter": "generic",
+ "stream": "ext://sys.stderr"
+ },
+ },
+ "formatters": {
+ "generic": {
+ "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
+ "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
+ "class": "logging.Formatter"
+ }
+ }
+}
+
+
+def loggers():
+ """ get list of all loggers """
+ root = logging.root
+ existing = list(root.manager.loggerDict.keys())
+ return [logging.getLogger(name) for name in existing]
+
+
+class SafeAtoms(dict):
+
+ def __init__(self, atoms):
+ dict.__init__(self)
+ for key, value in atoms.items():
+ if isinstance(value, str):
+ self[key] = value.replace('"', '\\"')
+ else:
+ self[key] = value
+
+ def __getitem__(self, k):
+ if k.startswith("{"):
+ kl = k.lower()
+ if kl in self:
+ return super().__getitem__(kl)
+ else:
+ return "-"
+ if k in self:
+ return super().__getitem__(k)
+ else:
+ return '-'
+
+
+def parse_syslog_address(addr):
+
+ # unix domain socket type depends on backend
+ # SysLogHandler will try both when given None
+ if addr.startswith("unix://"):
+ sock_type = None
+
+ # set socket type only if explicitly requested
+ parts = addr.split("#", 1)
+ if len(parts) == 2:
+ addr = parts[0]
+ if parts[1] == "dgram":
+ sock_type = socket.SOCK_DGRAM
+
+ return (sock_type, 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 = {
+ "critical": logging.CRITICAL,
+ "error": logging.ERROR,
+ "warning": logging.WARNING,
+ "info": logging.INFO,
+ "debug": logging.DEBUG
+ }
+ loglevel = logging.INFO
+
+ error_fmt = r"%(asctime)s [%(process)d] [%(levelname)s] %(message)s"
+ datefmt = r"[%Y-%m-%d %H:%M:%S %z]"
+
+ access_fmt = "%(message)s"
+ syslog_fmt = "[%(process)d] %(message)s"
+
+ atoms_wrapper_class = SafeAtoms
+
+ def __init__(self, cfg):
+ self.error_log = logging.getLogger("gunicorn.error")
+ self.error_log.propagate = False
+ self.access_log = logging.getLogger("gunicorn.access")
+ self.access_log.propagate = False
+ self.error_handlers = []
+ self.access_handlers = []
+ self.logfile = None
+ self.lock = threading.Lock()
+ self.cfg = cfg
+ self.setup(cfg)
+
+ def setup(self, cfg):
+ self.loglevel = self.LOG_LEVELS.get(cfg.loglevel.lower(), logging.INFO)
+ self.error_log.setLevel(self.loglevel)
+ self.access_log.setLevel(logging.INFO)
+
+ # set gunicorn.error handler
+ if self.cfg.capture_output and cfg.errorlog != "-":
+ for stream in sys.stdout, sys.stderr:
+ stream.flush()
+
+ self.logfile = open(cfg.errorlog, 'a+')
+ os.dup2(self.logfile.fileno(), sys.stdout.fileno())
+ os.dup2(self.logfile.fileno(), sys.stderr.fileno())
+
+ self._set_handler(self.error_log, cfg.errorlog,
+ logging.Formatter(self.error_fmt, self.datefmt))
+
+ # set gunicorn.access handler
+ if cfg.accesslog is not None:
+ self._set_handler(
+ self.access_log, cfg.accesslog,
+ fmt=logging.Formatter(self.access_fmt), stream=sys.stdout
+ )
+
+ # set syslog handler
+ if cfg.syslog:
+ self._set_syslog_handler(
+ self.error_log, cfg, self.syslog_fmt, "error"
+ )
+ if not cfg.disable_redirect_access_to_syslog:
+ self._set_syslog_handler(
+ self.access_log, cfg, self.syslog_fmt, "access"
+ )
+
+ if cfg.logconfig_dict:
+ config = CONFIG_DEFAULTS.copy()
+ config.update(cfg.logconfig_dict)
+ try:
+ dictConfig(config)
+ except (
+ AttributeError,
+ ImportError,
+ ValueError,
+ TypeError
+ ) as exc:
+ raise RuntimeError(str(exc))
+ elif cfg.logconfig_json:
+ config = CONFIG_DEFAULTS.copy()
+ if os.path.exists(cfg.logconfig_json):
+ try:
+ config_json = json.load(open(cfg.logconfig_json))
+ config.update(config_json)
+ dictConfig(config)
+ except (
+ json.JSONDecodeError,
+ AttributeError,
+ ImportError,
+ ValueError,
+ TypeError
+ ) as exc:
+ raise RuntimeError(str(exc))
+ elif cfg.logconfig:
+ if os.path.exists(cfg.logconfig):
+ defaults = CONFIG_DEFAULTS.copy()
+ defaults['__file__'] = cfg.logconfig
+ defaults['here'] = os.path.dirname(cfg.logconfig)
+ fileConfig(cfg.logconfig, defaults=defaults,
+ disable_existing_loggers=False)
+ else:
+ msg = "Error: log config '%s' not found"
+ raise RuntimeError(msg % cfg.logconfig)
+
+ def critical(self, msg, *args, **kwargs):
+ self.error_log.critical(msg, *args, **kwargs)
+
+ def error(self, msg, *args, **kwargs):
+ self.error_log.error(msg, *args, **kwargs)
+
+ def warning(self, msg, *args, **kwargs):
+ self.error_log.warning(msg, *args, **kwargs)
+
+ def info(self, msg, *args, **kwargs):
+ self.error_log.info(msg, *args, **kwargs)
+
+ def debug(self, msg, *args, **kwargs):
+ self.error_log.debug(msg, *args, **kwargs)
+
+ def exception(self, msg, *args, **kwargs):
+ self.error_log.exception(msg, *args, **kwargs)
+
+ def log(self, lvl, msg, *args, **kwargs):
+ if isinstance(lvl, str):
+ lvl = self.LOG_LEVELS.get(lvl.lower(), logging.INFO)
+ self.error_log.log(lvl, msg, *args, **kwargs)
+
+ def atoms(self, resp, req, environ, request_time):
+ """ Gets atoms for log formatting.
+ """
+ status = resp.status
+ if isinstance(status, str):
+ status = status.split(None, 1)[0]
+ atoms = {
+ 'h': environ.get('REMOTE_ADDR', '-'),
+ 'l': '-',
+ 'u': self._get_user(environ) or '-',
+ 't': self.now(),
+ 'r': "%s %s %s" % (environ['REQUEST_METHOD'],
+ environ['RAW_URI'],
+ environ["SERVER_PROTOCOL"]),
+ 's': status,
+ 'm': environ.get('REQUEST_METHOD'),
+ 'U': environ.get('PATH_INFO'),
+ 'q': environ.get('QUERY_STRING'),
+ 'H': environ.get('SERVER_PROTOCOL'),
+ 'b': getattr(resp, 'sent', None) is not None and str(resp.sent) or '-',
+ 'B': getattr(resp, 'sent', None),
+ 'f': environ.get('HTTP_REFERER', '-'),
+ 'a': environ.get('HTTP_USER_AGENT', '-'),
+ 'T': request_time.seconds,
+ 'D': (request_time.seconds * 1000000) + request_time.microseconds,
+ 'M': (request_time.seconds * 1000) + int(request_time.microseconds / 1000),
+ 'L': "%d.%06d" % (request_time.seconds, request_time.microseconds),
+ 'p': "<%s>" % os.getpid()
+ }
+
+ # add request headers
+ if hasattr(req, 'headers'):
+ req_headers = req.headers
+ else:
+ req_headers = req
+
+ if hasattr(req_headers, "items"):
+ req_headers = req_headers.items()
+
+ atoms.update({"{%s}i" % k.lower(): v for k, v in req_headers})
+
+ resp_headers = resp.headers
+ if hasattr(resp_headers, "items"):
+ resp_headers = resp_headers.items()
+
+ # add response headers
+ atoms.update({"{%s}o" % k.lower(): v for k, v in resp_headers})
+
+ # add environ variables
+ environ_variables = environ.items()
+ atoms.update({"{%s}e" % k.lower(): v for k, v in environ_variables})
+
+ return atoms
+
+ def access(self, resp, req, environ, request_time):
+ """ See http://httpd.apache.org/docs/2.0/logs.html#combined
+ for format details
+ """
+
+ if not (self.cfg.accesslog or self.cfg.logconfig or
+ self.cfg.logconfig_dict or self.cfg.logconfig_json or
+ (self.cfg.syslog and not self.cfg.disable_redirect_access_to_syslog)):
+ return
+
+ # wrap atoms:
+ # - make sure atoms will be test case insensitively
+ # - if atom doesn't exist replace it by '-'
+ safe_atoms = self.atoms_wrapper_class(
+ self.atoms(resp, req, environ, request_time)
+ )
+
+ try:
+ self.access_log.info(self.cfg.access_log_format, safe_atoms)
+ except Exception:
+ self.error(traceback.format_exc())
+
+ def now(self):
+ """ return date in Apache Common Log Format """
+ return time.strftime('[%d/%b/%Y:%H:%M:%S %z]')
+
+ def reopen_files(self):
+ if self.cfg.capture_output and self.cfg.errorlog != "-":
+ for stream in sys.stdout, sys.stderr:
+ stream.flush()
+
+ with self.lock:
+ if self.logfile is not None:
+ self.logfile.close()
+ self.logfile = open(self.cfg.errorlog, 'a+')
+ os.dup2(self.logfile.fileno(), sys.stdout.fileno())
+ os.dup2(self.logfile.fileno(), sys.stderr.fileno())
+
+ for log in loggers():
+ for handler in log.handlers:
+ if isinstance(handler, logging.FileHandler):
+ handler.acquire()
+ try:
+ if handler.stream:
+ handler.close()
+ handler.stream = handler._open()
+ finally:
+ handler.release()
+
+ def close_on_exec(self):
+ for log in loggers():
+ for handler in log.handlers:
+ if isinstance(handler, logging.FileHandler):
+ handler.acquire()
+ try:
+ if handler.stream:
+ util.close_on_exec(handler.stream.fileno())
+ finally:
+ handler.release()
+
+ def _get_gunicorn_handler(self, log):
+ for h in log.handlers:
+ if getattr(h, "_gunicorn", False):
+ return h
+
+ def _set_handler(self, log, output, fmt, stream=None):
+ # remove previous gunicorn log handler
+ h = self._get_gunicorn_handler(log)
+ if h:
+ log.handlers.remove(h)
+
+ if output is not None:
+ if output == "-":
+ h = logging.StreamHandler(stream)
+ else:
+ util.check_is_writable(output)
+ h = logging.FileHandler(output)
+ # make sure the user can reopen the file
+ try:
+ os.chown(h.baseFilename, self.cfg.user, self.cfg.group)
+ except OSError:
+ # it's probably OK there, we assume the user has given
+ # /dev/null as a parameter.
+ pass
+
+ h.setFormatter(fmt)
+ h._gunicorn = True
+ log.addHandler(h)
+
+ def _set_syslog_handler(self, log, cfg, fmt, name):
+ # setup format
+ prefix = cfg.syslog_prefix or cfg.proc_name.replace(":", ".")
+
+ prefix = "gunicorn.%s.%s" % (prefix, name)
+
+ # set format
+ fmt = logging.Formatter(r"%s: %s" % (prefix, fmt))
+
+ # syslog facility
+ try:
+ facility = SYSLOG_FACILITIES[cfg.syslog_facility.lower()]
+ except KeyError:
+ raise RuntimeError("unknown facility name")
+
+ # parse syslog address
+ socktype, addr = parse_syslog_address(cfg.syslog_addr)
+
+ # finally setup the syslog handler
+ h = logging.handlers.SysLogHandler(address=addr,
+ facility=facility, socktype=socktype)
+
+ h.setFormatter(fmt)
+ h._gunicorn = True
+ log.addHandler(h)
+
+ def _get_user(self, environ):
+ user = None
+ http_auth = environ.get("HTTP_AUTHORIZATION")
+ if http_auth and http_auth.lower().startswith('basic'):
+ auth = http_auth.split(" ", 1)
+ if len(auth) == 2:
+ try:
+ # b64decode doesn't accept unicode in Python < 3.3
+ # so we need to convert it to a byte string
+ auth = base64.b64decode(auth[1].strip().encode('utf-8'))
+ # b64decode returns a byte string
+ user = auth.split(b":", 1)[0].decode("UTF-8")
+ except (TypeError, binascii.Error, UnicodeDecodeError) as exc:
+ self.debug("Couldn't get username: %s", exc)
+ return user