繁体   English   中英

Python 结构日志 JSON

[英]Python Structlog JSON

我目前正在使用 python structlog JSONRenderer 并希望更改我的日志配置以将事件呈现为第一个 JSON 属性以提高可读性。

当前配置:

structlog.configure(processors=[structlog.processors.JSONRenderer()])
log = structlog.get_logger()

当前日志调用站点:

log.msg("Response: ",
                        content_type=content_type,
                        content_length=resp.headers.get('content-length'),
                        status_code=resp.status_code
                )

当前Output:

{"content_type": "application/json", "content_length": null, "status_code": 200, "event": "Response: "}

所需 Output:

{"event": "Response: ", "content_type": "application/json", "content_length": null, "status_code": 200}

任何帮助将不胜感激。

structlog.processors.JSONRenderer只是将日志 object 传递给json.dumps ,除非您指定另一个可调用对象:

structlog.configure(processors=[structlog.processors.JSONRenderer(serializer=mydumps)])

然后, mydumps将成为 function,它执行json.dumps所做的操作,但将event放在首位。 这可能看起来像:

def mydumps(dic,**kw):
   mod = {}
   if 'event' in dic:
      mod["event"] = dic["event"]
   for k in dic:
      if k!="event":
         mod[k] = dic[k]
   return json.dumps(mod,**kw)

What it does is to make a new object then look for event key in the input object and put it first to the new object then proceeding to put rest of keys into the object and pass it along with **kw to json.dumps .

请注意,这样您就不需要事先指定您的日志可能具有的其他键(如内容类型),因为任何事件类型都可能具有不同的信息。

看起来您可能使用的是比 3.6 更旧的 python 版本,它使键按插入顺序排列。 您可以使用KeyValueRenderer设置键顺序并使用OrderedDict作为 context_class:

from collections import OrderedDict

structlog.configure(
    processors=[
        structlog.processors.KeyValueRenderer(
            key_order=["event", "content_type", "content_length", "status_code"]
        ),
        structlog.processors.JSONRenderer()
    ],
    context_class = OrderedDict
)
log = structlog.get_logger()

参考: KeyValueRenderer

我通过重新使用结构日志中已有的内容,合并并改进了这两个答案。

批准的答案使用了我想避免的自定义 json 转储方法,另一个解决方案具有将日志从 JSON 转换为字符串的副作用,失去了很多用处。

在本地 shell 和远程服务器上工作的我的完整示例是:

import collections
import logging
import sys

import orjson
import structlog
from structlog.typing import EventDict, WrappedLogger


class ForcedKeyOrderRenderer(structlog.processors.KeyValueRenderer):
    """Based upon KeyValueRenderer but returns dict instead of string."""

    def __call__(self, _: WrappedLogger, __: str, event_dict: EventDict) -> str:
        sorted_dict = self._ordered_items(event_dict)
        return collections.OrderedDict(**{key: value for key, value in sorted_dict})


shared_processors = [
    structlog.contextvars.merge_contextvars,
    structlog.processors.add_log_level,
    structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=True),
]

if sys.stderr.isatty():
    processors = shared_processors + [
        structlog.processors.StackInfoRenderer(),
        structlog.dev.set_exc_info,
        structlog.dev.ConsoleRenderer(),
    ]
    logger_factory = None
else:  # pragma: no cover
    processors = shared_processors + [
        structlog.processors.format_exc_info,
        structlog.processors.dict_tracebacks,
        ForcedKeyOrderRenderer(
            sort_keys=True,
            key_order=[
                "event",
                "content_type",
                "content_length",
                "status_code",
            ],
            drop_missing=True,
        ),
        structlog.processors.JSONRenderer(serializer=orjson.dumps),
    ]
    logger_factory = structlog.BytesLoggerFactory()

if not structlog.is_configured():
    structlog.configure(
        cache_logger_on_first_use=True,
        wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
        processors=processors,
        logger_factory=logger_factory,
    )

logger = structlog.get_logger()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM