zoukankan      html  css  js  c++  java
  • python日志输出的内容修改为json格式

    业务中要求,python项目的日志输出为json串,同时包括异常;经过查看python logging相关的源码,发现还不能完全的兼容;比如异常的源码那里:

    class Formatter(object):
        """省略"""
        def format(self, record):
            record.message = record.getMessage()
            if self.usesTime():
                record.asctime = self.formatTime(record, self.datefmt)
            s = self.formatMessage(record)
            if record.exc_info:
                # Cache the traceback text to avoid converting it multiple times
                # (it's constant anyway)
                if not record.exc_text:
                    record.exc_text = self.formatException(record.exc_info)
            if record.exc_text:
                if s[-1:] != "
    ":
                    s = s + "
    "
                s = s + record.exc_text
            if record.stack_info:
                if s[-1:] != "
    ":
                    s = s + "
    "
                s = s + self.formatStack(record.stack_info)
            return s

    logging.Formatter的format方法,首先会按照格式化串格式化message,然后如果出现异常,是直接再message后面加上异常;此时格式已经不是指定的格式,因此这里需要修自定义。

    # -*- coding:utf-8 -*-
    import json
    import logging
    import os
    import traceback
    
    
    
    BASE_DIR = os.path.abspath(os.getcwd())
    LOG_DIR = os.path.join(BASE_DIR,  "logs")
    
    host_ip ="localhost"
    
    JSON_LOGGING_FORMAT = json.dumps({
        "ip": "%(ip)s",
        "app": "%(app)s",
        "level": "%(levelname)s",
        "trace": "%(stack_msg)s",
        "filepath": "%(pathname)s",
        "line_number": "%(lineno)s",
        "time": "%(asctime)s",
        "message": "%(message)s",
        "stack_trace": "%(exc_text)s"
    })
    
    
    class JsonLoggingFilter(logging.Filter):
        def __init__(self, name, ip, app):
            logging.Filter.__init__(self, name=name)
            self.ip = ip
            self.app = app
    
        def filter(self, record):
            record.ip = self.ip
            record.app = self.app
            # 为record 添加异常堆栈信息字段; 当有多个handler 的时候,这里会判断多次
            if hasattr(record, "stack_msg") and hasattr(record, "stack_trace"):
                return True
    
            if record.exc_info:
                ex_type, ex_val, ex_stack = record.exc_info
                stack_list = []
                for stack in traceback.extract_tb(ex_stack):
                    stack_list.append("%s" % stack)
    
                record.stack_msg = ex_val
                record.stack_trace = "#".join(stack_list)
            else:
                record.stack_msg, record.stack_trace = "", ""
    
            return True
    
    
    class JsonFormatter(logging.Formatter):
        def __init__(self, fmt=None):
            logging.Formatter.__init__(self, fmt=fmt)
    
        def format(self, record):
            record.message = record.getMessage()
            if self.usesTime():
                record.asctime = self.formatTime(record, self.datefmt)
    
            if record.exc_info:
                # Cache the traceback text to avoid converting it multiple times
                # (it's constant anyway)
                if not record.exc_text:
                    record.exc_text = self.formatException(record.exc_info).replace("
    ", " ").replace(""", "'")
    
            s = self.formatMessage(record)
            return s
    
    
    class JsonLogger(logging.Logger):
        logger = None
        level = None
        mode = None
    
        def __init__(self, app_name, level=logging.DEBUG, console_level=logging.INFO, mode="w"):
            self.name = app_name
            self.app_name = app_name
    
            logging.Logger.__init__(self, name=app_name)
    
            self.logger = logging.Logger(name=app_name)
            self.logger.setLevel(level)
    
            if not os.path.exists(LOG_DIR):
                os.makedirs(LOG_DIR)
            log_file_path = os.path.join(LOG_DIR, "%s.json" % app_name)
            json_logging_filter = JsonLoggingFilter(app_name, ip=host_ip, app=app_name)
            json_formatter = JsonFormatter(JSON_LOGGING_FORMAT)
    
            # 文件日志
            file_handle = logging.FileHandler(log_file_path, mode=mode)
            file_handle.setLevel(level)
            file_handle.setFormatter(json_formatter)
            file_handle.addFilter(json_logging_filter)
            # 控制台日志
            console_handle = logging.StreamHandler()
            console_handle.setLevel(console_level)
            console_handle.setFormatter(json_formatter)
            console_handle.addFilter(json_logging_filter)
    
            self.logger.addHandler(file_handle)
            self.logger.addHandler(console_handle)
    
        def getLogger(self):
            return self.logger
    
        def setLevel(self, level):
            self.logger.level = level
    
    
    if __name__ == '__main__':
        my_logger = JsonLogger("python-common").getLogger()
        my_logger.info("info  level log")
        try:
            open('/path/to/does/not/exist', 'rb')
        except FileNotFoundError as e:
            my_logger.exception("file exception", exc_info=e)

    参考:

    https://www.cnblogs.com/yyds/p/6901864.html

    关于异常 https://www.jianshu.com/p/b342b19657fc

    日志输出 json串 https://blog.csdn.net/diqiuyi7777/article/details/86498203

  • 相关阅读:
    实习第一天
    附加、分离数据库和备份、还原数据库的区别(转载于中雪的BLOG)
    2014-08-29 Last Day
    2014-08-26 解决HttpContext.Current.Session在ashx文件中出现“未将对象引用设置到对象的实例”的问题
    什么是Ajax? (转载于疯狂客的BLOG)
    Response.Expires 属性 (转载于疯狂客的BLOG)
    2014-08-22 关于Response、Request等对象在cs文件中的使用
    ASP.NET获取IP的6种方法(转载于LanceZhang's Tech Blog)
    2014-08-13 SQL语句之Left Join
    2014-08-07 优秀程序员所应具备的思想
  • 原文地址:https://www.cnblogs.com/dasheng-maritime/p/11715746.html
Copyright © 2011-2022 走看看