Skip to content

Commit 64266e5

Browse files
committed
Add args to structured output
Signed-off-by: Vadim Markovtsev <vadim@poolside.ai>
1 parent 3f66949 commit 64266e5

1 file changed

Lines changed: 23 additions & 7 deletions

File tree

flogging/flogging.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ def decorated_with_check_trailing_dot(*args):
128128
msg = record.msg
129129
if isinstance(msg, str) and msg.endswith(".") and not msg.endswith(".."):
130130
err_msg = (
131-
f"Log message is not allowed to have a trailing dot:"
132-
f' {record.name}: "{msg}"'
131+
f'Log message is not allowed to have a trailing dot: {record.name}: "{msg}"'
133132
)
134133
raise AssertionError(err_msg)
135134
args = list(args)
@@ -189,15 +188,20 @@ class StructuredHandler(logging.Handler):
189188

190189
"""logging handler for structured logging."""
191190

192-
default_fields = set(logging.LogRecord("", logging.NOTSET, "", 1, "msg", (), None).__dict__)
191+
default_fields = set(
192+
logging.LogRecord("", logging.NOTSET, "", 1, "msg", (), None).__dict__
193+
).union({"discard_msg", "discard_args"})
193194

194195
def __init__(
195-
self, level=logging.NOTSET, level_from_msg: Callable[[str], str | None] | None = None
196+
self,
197+
level=logging.NOTSET,
198+
level_from_msg: Callable[[str], str | None] | None = None,
196199
):
197200
"""Initialize a new StructuredHandler."""
198201
super().__init__(level)
199202
self.local = threading.local()
200203
self.level_from_msg = level_from_msg if level_from_msg is not None else lambda _: None
204+
self.json = json
201205

202206
def emit(self, record: logging.LogRecord): # noqa: PLR0912
203207
"""Print the log record formatted as JSON to stdout."""
@@ -210,17 +214,20 @@ def emit(self, record: logging.LogRecord): # noqa: PLR0912
210214
level = level.lower()
211215
if msg.startswith("{"):
212216
try:
213-
msg = json.loads(msg)
217+
msg = self.json.loads(msg)
214218
except json.JSONDecodeError:
215219
pass
216220
obj = {
217221
"level": level,
218-
"msg": msg,
219222
"source": "%s:%d" % (record.filename, record.lineno),
220223
"time": format_datetime(created),
221224
"thread": reduce_thread_id(record.thread),
222225
"name": record.name,
223226
}
227+
if not getattr(record, "discard_msg", False):
228+
obj["msg"] = msg
229+
if not getattr(record, "discard_args", False):
230+
obj["args"] = record.args
224231
obj.update((k, getattr(record, k)) for k in record.__dict__.keys() - self.default_fields)
225232
try:
226233
rank = os.environ["RANK"]
@@ -237,12 +244,21 @@ def emit(self, record: logging.LogRecord): # noqa: PLR0912
237244
obj["context"] = self.local.context
238245
except AttributeError:
239246
pass
240-
print(json.dumps(obj, sort_keys=True), file=sys.stdout, flush=True) # noqa: T201
247+
print( # noqa: T201
248+
self.json.dumps(obj, sort_keys=True, default=self.json_fallback),
249+
file=sys.stdout,
250+
flush=True,
251+
)
241252

242253
def flush(self):
243254
"""Write all pending text to stdout."""
244255
sys.stdout.flush()
245256

257+
@classmethod
258+
def json_fallback(cls, obj) -> str:
259+
"""Format an object that `StructuredHandler.json` doesn't support."""
260+
return f"<{type(obj).__name__}>"
261+
246262

247263
def setup(
248264
level: str | int | None = os.environ.get("LOG_LEVEL", "INFO"),

0 commit comments

Comments
 (0)