zoukankan      html  css  js  c++  java
  • Node.js / Python 日志

    一、Node.js 日志


    1、原生

    Node.js 原生方法其实很简单,就四个:

    // 输出到 stdout
    console.log()
    console.info() = console.log()
    
    // 输出到 stderr
    console.warn()
    console.error() = console.warn()
    

    配合 pm2 的 log 功能(参见我之前的 blog:pm2 官方文档学习笔记- 小蒋不素小蒋- 博客园),可以对项目实现基础的日志功能。(目前我采用的也是这种)

    2、第三方库

    debug:比较简单,express 有用到

    log4js:比debug复杂,比肩winston

    winston:拥有强大的社区支持不同的日志模块

    bunyan:更适用于复杂的日志处理,但是需要用户自定义

    以上库我都没怎么用过,具体待写。

    3、思考

    一个好的日志(系统),最好满足下面条件:

    1、能按重要程度分级:例如分FATALERRORWARNINFODEBUG 等级。

    2、能按所属功能分级:例如:

    • stat: 系统性能统计日志,应用会定时收集一些性能信息,便于查询应用当前状态
    • visit: 每个http请求相关的日志,会包含惟一的 requestId,定位该请求相关的所有日志
    • biz: 业务数据相关日志,主要提供给数据统计使用

    3、日志格式统一,最好采用 JSON ,便于 ELK 解析处理。

    Elasticsearch + Logstash + Kibana(ELK)是一套开源的日志管理方案。

    4、支持多种输出类型,例如 console、文件。

    5、支持过滤规则

    6、分布式集中采集。应用一般都是分布式的,但是日志不能是分布式。

    7、报警功能。如有 ERROR / FATAL 级别的日志,则发邮件、短信提醒。

    8、随时一键打开或关闭

    9、可读性强,例如有染色能力

    10、支持分割日志、定期备份

    11、能重现现场(如还原成 fiddler抓包),对于概率性问题保留现场再重要不过。

    二、python 日志


    1、原生

    (1)介绍

    1、python 的日志功能包括:

    • Logger 记录器:这是我们能对整个对 Logging 进行操作的对象。要输出Logging 一定要一个Logger,当然导入 logging 之后有一个默认 logging 为 root logger。

    • Handler 处理器:将(日志记录器产生的)日志记录发送至合适的目的地。

    • Filter 过滤器:提供了更好的粒度控制,它可以决定输出哪些日志记录。

    • Formatter 格式化器:指明了最终输出中日志记录的布局。

    注意:

    • Logger 可以包含很多 Handler/Filter,Handler 可以包含很多 Handler/Filter/Formatter

    • 如果不通过logger = logging.getLogger(name)来创建 Logger,则采用默认的Logger,名为 root

    • Logger 会有个默认的 Handler ,将日志打印到 console 上 (stdout)。

    • Formatter 默认的时间格式为 %Y-%m-%d %H:%M:%S。


    2、python 的日志级别分为:

    级别 何时使用
    DEBUG 详细信息,典型地调试问题时会感兴趣。
    INFO 证明事情按预期工作。
    WARNING 表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。
    ERROR 由于更严重的问题,软件已不能执行一些功能了。
    CRITICAL 严重错误,表明软件已不能继续运行了。

    注意:

    • Logger 和 Handler 都可以指定日志级别,Handler 优先级最高。

    • 默认的日志级别为 WARNING。(即高于 WARNING 才会输出)

    (2)使用方式
    • 1、缺省使用不配置;
    • 2、显式创建记录器 Logger、处理器 Handler 和格式化器 Formatter,并进行相关设置;
    • 3、通过简单方式进行配置,使用basicConfig()函数直接进行配置;
    • 4、通过配置文件进行配置,使用fileConfig()函数读取配置文件;
    • 5、通过配置字典进行配置,使用dictConfig()函数读取配置信息;
    • 6、通过网络进行配置,使用listen()函数进行网络配置。

    1、缺省配置

    import logging
    
    logging.debug('debug message')
    logging.info('info message')
    logging.warning('warn message')
    logging.error('error message')
    logging.critical('critical message')
    

    如上所述,默认日志级别为 WARNING,输出到 console 上 (stdout)。

    输出:

    格式为日志级别 :logger实例名称 :日志消息内容

    WARNING:root:warn message
    ERROR:root:error message
    CRITICAL:root:critical message
    

    2、显式创建

    import logging
    
    # 记录器
    logger = logging.getLogger("logger")
    
    # 处理器 - 常用的有两个
    handler1 = logging.StreamHandler()
    handler2 = logging.FileHandler(filename="test.log")
    
    # 指定 Level
    handler1.setLevel(logging.WARNING)
    handler2.setLevel(logging.DEBUG)
    # logger.setLevel(logging.DEBUG)
    
    # 格式化器
    fmt = "%(asctime)-15s %(levelname)s %(filename)s %(lineno)d %(process)d %(message)s"
    datefmt = "%a %d %b %Y %H:%M:%S"
    formatter = logging.Formatter(fmt, datefmt)
    handler1.setFormatter(formatter)
    handler2.setFormatter(formatter) 
    # logger.setFormatter(formatter) 注意:这样不行!
    
    # 过滤器
    class NoParsingFilter(logging.Filter):
        def filter(self, record):
            return not record.getMessage().startswith('This is an')
            
    handler1.addFilter(NoParsingFilter())
    handler2.addFilter(NoParsingFilter())
    # logger.addFilter(NoParsingFilter())
    
    # 处理器 -- 绑定 -> 记录器
    logger.addHandler(handler1)
    logger.addHandler(handler2)
    
    # exec 
    logger.debug('This is a customer debug message')
    logger.info('This is an customer info message')
    logger.warning('This is a customer warning message')
    logger.error('This is an customer error message')
    logger.critical('This is a customer critical message')
    

    format格式:

    格式 描述
    %(levelno)s 打印日志级别的数值
    %(levelname)s 打印日志级别名称
    %(pathname)s 打印当前执行程序的路径
    %(filename)s 打印当前执行程序名称
    %(funcName)s 打印日志的当前函数
    %(lineno)d 打印日志的当前行号
    %(asctime)s 打印日志的时间
    %(thread)d 打印线程id
    %(threadName)s 打印线程名称
    %(process)d 打印进程ID
    %(message)s 打印日志信息

    输出:

    Sun 17 Nov 2019 23:01:22 WARNING test.py 35 70560 This is a customer warning message
    Sun 17 Nov 2019 23:01:22 CRITICAL test.py 37 70560 This is a customer critical message
    

    3、basicConfig() 配置

    可快速创建 logger。

    import logging
    
    logging.basicConfig(filename="test.log", filemode="w", format="%(asctime)s %(name)s:%(levelname)s:%(message)s", datefmt="%d-%M-%Y %H:%M:%S", level=logging.DEBUG)
    
    logging.debug('debug message')
    logging.info('info message')
    logging.warning('warn message')
    logging.error('error message')
    logging.critical('critical message')
    

    basicConfig 的配置项如下:

    关键字 描述
    filename 创建一个FileHandler,使用指定的文件名,而不是使用StreamHandler。
    filemode 如果指明了文件名,指明打开文件的模式(如果没有指明filemode,默认为'a')。
    format handler使用指明的格式化字符串。
    datefmt 使用指明的日期/时间格式。
    level 指明根logger的级别。
    stream 使用指明的流来初始化StreamHandler。该参数与'filename'不兼容,如果两个都有,'stream'被忽略。

    输出:

    17-03-2019 23:03:58 root:DEBUG:debug message
    17-03-2019 23:03:58 root:INFO:info message
    17-03-2019 23:03:58 root:WARNING:warn message
    17-03-2019 23:03:58 root:ERROR:error message
    17-03-2019 23:03:58 root:CRITICAL:critical message
    

    4、5、6 待写。

    (3)其它

    1、log 如何记录错误栈信息

    a = 5
    b = 0
    try:
        c = a / b
    except Exception as e:
        # 这种写法记录不到错误栈信息
        # logging.error("Exception occurred")
    
        # 下面三种方式三选一 
        # logging.exception("Exception occurred")
        # logging.error("Exception occurred", exc_info=True)
        # logging.log(level=logging.ERROR, msg="Exception occurred", exc_info=True)
    
    
  • 相关阅读:
    LeetCode刷题之字符串
    LeetCode刷题之数组复习
    为什么要用移码来表示阶码(指数)呢?
    字节左移跟右移
    一个有趣的问题
    为什么对数组名取地址,得到的为整个数组的地址?
    在win10 64位下搭建汇编环境
    windows切换samba账号进行连接
    samba服务配置记录
    subversion钩子函数使用记录
  • 原文地址:https://www.cnblogs.com/xjnotxj/p/11879146.html
Copyright © 2011-2022 走看看