Python logging handler概述
Python logging 模块提供了一套灵活的日志记录系统,允许开发者在应用程序中记录不同级别的消息,如调试信息、警告、错误等。使用Python SDK提供的logging Handler可以使Python程序在日志在不落盘的情况下自动上传到日志服务上,这种上传方式具有实时性、异步性、吞吐量大、配置简单等特点。使用这部分功能,只需要配置handler目录下的logging.ini 内的几个关键配置即可直接使用。
使用步骤
1、安装ctyun-lts-python-sdk:1.6.0,目录中包含ctyun-lts-python-sdk-1.6.0.tar.gz。
pip install ctyun-lts-python-sdk-1.6.0.tar.gz
如果安装失败,可单独安装requirements_py3.txt,详情可参考python SDK 概述-2.2下载和安装。
pip install -r requirements_py3.txt
2、修改handler 中的 logging.ini 中的自定义配置,里面包含了与日志上传服务相关的5个参数,这和使用SDK上传日志类似。
;替换下面5个参数
args=('your endpoint','your access_key','your secret_key', 'log_project', 'log_unit',)
3、执行example/sample_logging_handler.py 示例即可。
logging.ini 配置
在用例中自定义配置了三种handler :consoleHandler、asyncHandler、syncHandler。
1、consoleHandler的配置中class=StreamHandler,这代表会将logger 日志输出到控制台。
2、syncHandler 配置中的 class=handler.AsyncHandler,这代表handler 将会去使用SyncHandler 类的配置进行日志上传,这个类使用的是同步单线程将logger 的日志上传到云日志服务中。
3、asyncHandler配置中的 class=handler.AsyncHandler,这代表handler 将会去使用AsyncHandler 类的配置进行日志上传,这个类使用的是异步批量多线程方式将logger 的日志上传到云日志服务中。
用户使用这个功能的时候,需要修改handler 中的args 配置。里面包含了与日志上传服务相关的5个参数,这和使用SDK上传日志类似。
;替换下面5个参数
args=('your endpoint','your access_key','your secret_key', 'log_project', 'log_unit',)
;使用环境变量
;args=(os.environ.get('LTS_ENDPOINT', '',),os.environ.get('LTS_ACCESSKEY', ''),
os.environ.get('LTS_SECRETKEY', ''),os.environ.get('LTS_LOGPROJECT', ''),
os.environ.get('LTS_LOGUNIT', ''))
当然如果对安全性要求较高,强烈建议不要将明文access_key 和 secret_key 写在logging.ini配置中,代替使用系统变量存放。可使用args=(os.environ.get('LTS_ENDPOINT', '',)获取系统变量。
[loggers]
keys=root,sync_logging,async_logging
[handlers]
keys=consoleHandler, asyncHandler,syncHandler
[formatters]
keys=consoleFormatter,ltsFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_async_logging]
level=INFO
handlers=consoleHandler,asyncHandler
qualname=async_logging
propagate=0
[logger_sync_logging]
level=INFO
handlers=consoleHandler,syncHandler
qualname=sync_logging
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=consoleFormatter
args=(sys.stdout,)
[handler_asyncHandler]
class=handler.AsyncHandler
formatter=ltsFormatter
;替换下面5个参数
args=('your endpoint','your access_key','your secret_key', 'log_project', 'log_unit',)
[handler_syncHandler]
class=handler.SyncHandler
formatter=ltsFormatter
;替换下面5个参数
args=('your endpoint','your access_key','your secret_key', 'log_project', 'log_unit',)
[formatter_consoleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
[formatter_ltsFormatter]
format=%(asctime)s - %(levelname)s - %(threadName)s - %(filename)s[line:%(lineno)d] - %(message)s
log handler 的使用示例
在完成前面logging.ini 的配置之后,就可以直接使用本服务将logger 日志直接上传到云日志服务中去。由于定义的三个handler功能各不同,使用时也有细微差异。
示例代码:log handler 使用(example 目录下的 sample_logging_handler.py)
import logging.config
import time
# 加载logging.ini配置文件
logging.config.fileConfig("../handler/logging.ini")
# 获取logger实例,异步发送logger日志
logger = logging.getLogger('async_logging')
# 获取logger实例,同步发送logger日志
logger2 = logging.getLogger('sync_logging')
# 获取logger实例,将日志输出到日志控制台
logger3 = logging.getLogger()
logger.info("log message,level:info")
logger.warning("log message,level:warning")
logger.error("log message,level:error")
try:
result = 10 / 0 # 可能引发异常的代码
except Exception as e:
# 或者
logger.error("An error occurred: ", exc_info=True) # 采集异常信息
logger2.info("log2 message,level:info")
logger2.error("log2 message,level:error")
logger3.debug("log2 message,level:debug")
logger3.info("log2 message,level:info")
logger3.error("log2 message,level:error")
time.sleep(5)
logging.shutdown()
日志格式如下所示:其中__ user_agent 、__ ts 、__ message__ 是云日志服务的固定字段,其余字段是将message进行分词处理后的字段。
__user_agent__ : lts-python-logging-handler/1.5.1
exception : {错误信息,此处省略} ZeroDivisionError: division by zero
file_name : sample_logging_handler.py
level : ERROR
message : An error occurred:
thread : MainThread
time : 2024-06-21,17:52:48
__ts__ : 2024-06-21 17:52:48.920
__message__ : 2024-06-21 17:52:48,920 - ERROR - MainThread - sample_logging_handler.py[line:26] - An error occurred: {错误信息,此处省略}
加载logging.ini配置
此操作是用于加载logging.ini 配置文件,文件处于handler 目录下。加载这份配置才能够使用后续功能。
logging.config.fileConfig("../handler/logging.ini")
获取logger 实例:root
此操作是用于使用原生的logger 功能,即不将logger日志上传到云日志服务。其中root参数可以省略。
logger = logging.getLogger()
# 下面这个格式也生效
logger = logging.getLogger('root')
# logger 使用
logger.info("log message,level:info")
获取logger 实例:sync_logging
此操作是使用同步单线程的形式将logger日志上传到云日志服务(同时也会输出到控制台),这种方式调用logger生成一条日志,就会发送一次http请求将日志上传。这种方式简单,但当调用频率很高时,会出现阻塞情况,发送效率不高。
logger = logging.getLogger('sync_logging')
logger.info("sync log message 1,level:info")
logger.info("sync log message 2,level:info")
logger.info("sync log message 3,level:info")
获取logger 实例:async_logging
此操作是使用异步批量多线程的形式将logger日志上传到云日志服务(同时也会输出到控制台),这种方式调用logger生成一条日志后,会发送到一个日志累加器内,当日志累加器的日志量超过预设的大小或条数,或者等待指定时间后,日志累加器的日志会被打包成一个任务,然后开启一个线程将这些日志一次批量发送到云日志服务。这种方式效率高,异步非阻塞,非常适合需要频繁上传日志的场景。
logger = logging.getLogger('async_logging')
logger.info("async log message 1,level:info")
logger.info("async log message 2,level:info")
logger.info("async log message 3,level:info")
捕获异常信息Exception
此操作是当发送异常时,可以使用logger.error()将异常信息也进行上传。这种方式可以有效记录异常发生时的情况。其中需要配置exc_info=True这个参数。
try:
result = 10 / 0
except Exception as e:
logger.error("An error occurred:" exc_info=True)
修改日志上传的level级别
修改logging.ini 配置中对应的level为WARN 则只上传WARN及以上级别日志
[logger_async_logging]
level=WARN
handlers=consoleHandler,asyncHandler
qualname=async_logging
propagate=0
Logging.shutdown()
此操作是关闭所有的logger,使用这个方法会关闭所有日志,除了原生的logger.getLogger()。如果使用了async_logging 这个异步上传的handler,请在不需要使用的时候调用logging.shutdown()方法进行关闭,这样可以有效减少资源消耗。
logging.shutdown()