本文档为您介绍如何使用Log Handler自动上传Python日志。

概述

使用Python SDK提供的Log Handler可以实现每一条Python程序的日志在不落盘的情况下自动上传到日志服务。与写到文件再通过各种方式上传比起来,有如下优势。
  • 实时性强,主动直接发送,不落盘。
  • 吞吐量大,异步发送。
  • 配置简单,无需修改程序,无需知道机器位置,修改程序配置文件即可生效。
  • 智能解析,自动解析日志中JSON和KV格式信息。

本文档主要介绍基本的配置方式,关于如何自动解析JSON和KV格式的日志和相关配置,请参见自动上传KV格式日志自动上传JSON格式日志

配置

Log Handler与Python logging模块完全兼容,请参见Python Logging

Python logging模块允许通过编程或者文件的形式配置日志,如下我们通过文件logging.conf配置。
[loggers]
keys=root,sls

[handlers]
keys=consoleHandler, slsHandler

[formatters]
keys=simpleFormatter, rawFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_sls]
level=INFO
handlers=consoleHandler, slsHandler
qualname=sls
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[handler_slsHandler]
class=aliyun.log.QueuedLogHandler
level=INFO
formatter=rawFormatter
args=(os.environ.get('ALIYUN_LOG_SAMPLE_ENDPOINT', ''), os.environ.get('ALIYUN_LOG_SAMPLE_ACCESSID', ''), os.environ.get('ALIYUN_LOG_SAMPLE_ACCESSKEY', ''), os.environ.get('ALIYUN_LOG_SAMPLE_TMP_PROJECT', ''), "logstore")

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s


[formatter_rawFormatter]
format=%(message)s
此处我们配置了一个root和一个sls的Log Handler,其中sls是实例化类aliyun.log.QueuedLogHandler,并传入如下参数。详细参数请参见详细参数列表
args=(os.environ.get('ALIYUN_LOG_SAMPLE_ENDPOINT', ''), os.environ.get('ALIYUN_LOG_SAMPLE_ACCESSID', ''), os.environ.get('ALIYUN_LOG_SAMPLE_ACCESSKEY', ''), os.environ.get('ALIYUN_LOG_SAMPLE_TMP_PROJECT', ''), "logstore")
说明 这里使用了os.environ从环境变量中获取相关配置。您也可以直接填写实际的值。

上传日志

使用logging配置文件并输出日志即可。
import logging
import logging.config

# 配置
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('sls')

# 使用logger
logger.info("test1")

try:
    1/0
except ZeroDivisionError as ex:
    logger.exception(ex)

之后日志即可自动上传到日志服务。如果要使用统计查询功能,请打开索引。

配置日志服务Logstore的索引

将接收日志的Logstore的索引打开,将特定域进行索引。推荐使用命令行工具CLI进行如下配置。
aliyunlog log update_index --project_name="project1" --logstore_name="logstore1" --index_detail="file:///Users/user1/loghandler_index.json"

配置文件请参见python_logging_handler_index.json

调整收集日志域

目前支持如下的日志信息,默认会收集所有相关域。
说明
message 消息内容。
record_name logging handler的名字,上面例子是sls
level 级别,INFO、ERROR等。
file_path 代码文件全路径。
func_name 所在函数名。
line_no 行号。
module 所在模块。
thread_id 当前线程Id。
thread_name 当前线程名。
process_id 当前进程Id。
process_name 当前进程名。

参考QueuedLogHandler的参数fields接收一个列表来调整想要配置的域。具体请参见日志域列表

下面例子中,我们修改之前的日志配置文件,只收集个别域如module、func_name等。
[handler_slsHandler]
class=aliyun.log.QueuedLogHandler
level=INFO
formatter=rawFormatter
args=('cn-beijing.log.aliyuncs.com', 'ak_id', 'ak_key', 'project1', "logstore1", 'mytopic', ['level', 'func_name', 'module', 'line_no']  )
说明
  • message是一定会被收集的。
  • 您也可以通过参数buildin_fields_prefixbuildin_fields_suffix给这些内置域增加前缀和后缀。例如__level__等。

使用JSON配置

如果期望更加灵活的配置,也可以使用代码配置。
#encoding: utf8
import logging, logging.config, os

# 配置
conf = {'version': 1,
        'formatters': {'rawformatter': {'class': 'logging.Formatter',
                                        'format': '%(message)s'}
                       },
        'handlers': {'sls_handler': {'()':
                                     'aliyun.log.QueuedLogHandler',
                                     'level': 'INFO',
                                     'formatter': 'rawformatter',

                                     # custom args:
                                     'end_point': os.environ.get('ALIYUN_LOG_SAMPLE_ENDPOINT', ''),
                                     'access_key_id': os.environ.get('ALIYUN_LOG_SAMPLE_ACCESSID', ''),
                                     'access_key': os.environ.get('ALIYUN_LOG_SAMPLE_ACCESSKEY', ''),
                                     'project': 'project1',
                                     'log_store': "logstore1"
                                     }
                     },
        'loggers': {'sls': {'handlers': ['sls_handler', ],
                                   'level': 'INFO',
                                   'propagate': False}
                    }
        }
logging.config.dictConfig(conf)

# 使用
logger = logging.getLogger('sls')
logger.info("Hello world")
说明 QueuedLogHandler的初始化方式,用的是传入命名参数的方式。具体参数列表可以参见这里

更多关于Python的dictConfig,参见dictConfig

UWSGI下使用Python Logging Handler

这里主要介绍了QueuedLogHandler,但是在UWSGI下因为进程调度模型的原因,这个类无法正常工作。因此提供了如下另外2个Handler。
  • UwsgiQueuedLogHandler:推荐使用这个类,功能和配置完全一样。但是需要额外安装一个第三方法库uwsgidecorators
  • SimpleLogHandler:即时发送的简单Logging Handler,配置完全一样。用于特殊场景下的测试更方便一些,一般情况下不推荐。