structlog
structlog copied to clipboard
Add a helper function for systemd's SyslogLevelPrefix
From systemd.exec(5):
SyslogLevelPrefix=
Takes a boolean argument. If true and StandardOutput= or StandardError= are set to syslog, kmsg or journal, log lines written by the executed process that are prefixed with a log level will be passed on to syslog with this log level set but the prefix removed. If set to false, the interpretation of these prefixes is disabled and the logged lines are passed on as-is. For details about this prefixing see sd-daemon(3). Defaults to true.
i.e. for the simple case where a service emits output to stdout, and systemd picks that up, it may be helpful to add a prefix with the syslog log level. systemd will also pick that up, strip it from its output, and use it as the log level, by default.
There are two parts to this:
- Adding the syslog log level to
event_dict, i.e. "4" (orsyslog.LOG_WARNING) for "warn"/"warning", etc. Python's logging.handlers.SysLogHandler has code for that, and python-systemd is trying to do something more clever to cover custom log levels. Neither are reusable, but should be simple to implement. It should be similar to the existingadd_log_level_numberprocessor. - A simple processor that prepends the
eventmessage with said level. I'm guessing that will be more controversial though. Alternatively, it could also be an argument to PrintLogger.
The "syslog" log level will also be useful in case one e.g. wants to write a processor using the stdlib syslog module (i.e. without involving logging).
(1) would probably be something like that. Let me know what you think :)
diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py
index edaeccd..03e5fe6 100644
--- a/src/structlog/stdlib.py
+++ b/src/structlog/stdlib.py
@@ -343,6 +343,18 @@ _NAME_TO_LEVEL = {
"notset": NOTSET,
}
+# see syslog(3) and logging.handler.SysLogHandler for a similar mapping
+_NAME_TO_SYSLOG_LEVEL = {
+ "critical": 2, # LOG_CRIT
+ "error": 3, # LOG_ERR
+ "exception": 3, # LOG_ERR
+ "warn": 4, # LOG_WARNING
+ "warning": 4, # LOG_WARNING
+ "info": 6, # LOG_INFO
+ "debug": 7, # LOG_DEBUG
+ "notset": 7, # LOG_DEBUG
+}
+
_LEVEL_TO_NAME = {
v: k
for k, v in _NAME_TO_LEVEL.items()
@@ -406,6 +418,14 @@ def add_log_level_number(logger, method_name, event_dict):
return event_dict
+def add_syslog_level(logger, method_name, event_dict):
+ """
+ Add the syslog level (0-7) to the event dict.
+ """
+ event_dict["syslog_level"] = _NAME_TO_SYSLOG_LEVEL[method_name]
+ return event_dict
+
+
def add_logger_name(logger, method_name, event_dict):
"""
Add the logger name to the event dict.
Looks useful I guess? 🤔 Any idea how to test that?