测试代码的文件结构为:
.
├── sub_dir
│ ├── __init__.py
│ ├── test_logger02.py
│ └── sub_sub_dir
│ ├── __init__.py
│ └── test_logger03.py
├── test_logger01.py
└── test_logger.py
test_logger.py 代码如下:
import functools
import logging
import os
import sys
from termcolor import colored
from sub_dir.sub_sub_dir.test_logger03 import test_logger03
from sub_dir.test_logger02 import test_logger02
from test_logger01 import test_logger01
# 等级由低到高分别是:DEBUG、INFO、WARNING、ERROR、CRITICAL
@functools.lru_cache()
def create_logger(
output_dir,
level="INFO", # 设置记录等级,高于等于此等级的会被记录
name="", # logger名字,通常是以点号分隔的带层级结构的名如'a'、'a.b'或 'a.b.c.d' a.b 的日志也会被记录到 a 日志中
description="",
):
# create logger
logger = logging.getLogger(name)
logger.setLevel(getattr(logging, level))
logger.propagate = False
# create console handlers for master process
color_fmt = (
colored("[%(asctime)s]", "green")
+ colored("(%(filename)s %(lineno)d)", "yellow")
+ "%(levelname)s: %(message)s"
)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(getattr(logging, level)) # 大于等于level的信息才会被记录
console_handler.setFormatter(
logging.Formatter(fmt=color_fmt, datefmt="%m-%d %H:%M")
)
logger.addHandler(console_handler)
# create file handlers
file_fmt = "[%(asctime)s](%(filename)s %(lineno)d)%(levelname)s: %(message)s"
file_handler = logging.FileHandler(
os.path.join(output_dir, "logs.txt"), mode="a", encoding="utf-8"
)
file_handler.setLevel(getattr(logging, level)) # 大于等于level的信息才会被记录
file_handler.setFormatter(logging.Formatter(fmt=file_fmt, datefmt="%m-%d %H:%M"))
logger.addHandler(file_handler)
logger.info("|+|+|+|+|++++++--------(T^_^T)--------++++++|+|+|+|+|")
logger.info(description)
return logger
if __name__ == "__main__":
# ---------第一种创建方法
# name = __name__
# name = "sub_dir"
# logger = create_logger(output_dir=".", name=name, level="INFO")
# ---------第二种创建方法
logger = logging.getLogger(__name__)
logging.basicConfig(filename="logs.txt", level=logging.INFO)
# ---------第三种创建方法
# logger = create_logger(output_dir=".", name="", level="INFO")
# 第一种方法,通过 name 的设置,相当于对指定模块进行配置,没有对 root logger 进行设置,所以输出中只会有指定模块中logger和他子级的东西。
# 第二种方法,虽然定义的不是 root,但是通过 BasicConfig 设置了 root logger 的配置,所以输出中会有所有模块的东西。(所有东西在指定的文件里,命令行输出需要额外设置)
# 第三种方法,将 name 设为空或者 None,这样再进行设置就是对 root logger 进行设置了。输出会有所有模块logger中的东西。
logger.info("Started")
test_logger01()
test_logger02()
test_logger03()
logger.info("Finished")
test_logger01. py 代码如下:
import logging
_logger = logging.getLogger(__name__)
def test_logger01():
# _logger.info("test_logger01")
# _logger.debug("test_logger01")
# _logger.warning("test_logger01")
# _logger.error("test_logger01")
# _logger.critical("test_logger01")
# _logger.info("test_logger01: " + str(__name__))
_logger.info("test_logger01: " + str(_logger))
test_logger02. py 代码如下:
import logging
_logger = logging.getLogger(__name__)
def test_logger02():
# _logger.info("test_logger02")
# _logger.debug("test_logger02")
# _logger.warning("test_logger02")
# _logger.error("test_logger02")
# _logger.critical("test_logger02")
# _logger.info("test_logger02: " + str(__name__))
_logger.info("test_logger02: " + str(_logger))
test_logger03. py 代码如下:
import logging
_logger = logging.getLogger(__name__)
def test_logger03():
# _logger.info("test_logger03")
# _logger.debug("test_logger03")
# _logger.warning("test_logger03")
# _logger.error("test_logger03")
# _logger.critical("test_logger03")
# _logger.info("test_logger03: " + str(__name__))
_logger.info("test_logger03: " + str(_logger))
创建 logger 代码中,添加了输出方式为命令行输出和 txt 文件输出。创建时候 name 参数为空或者 none,创建的是 RootLogger,名字为 root,level 为 WARNING。
以下为官方说明:
name 一般是以句点分割的层级值,如 foo. bar. baz (尽管也可以是简单形式,例如 foo)。层级结构列表中位于下方的日志记录器是列表中较高位置的日志记录器的子级。例如,假定有一个名叫 foo 的日志记录器,则名字为 foo. bar, foo. bar. baz 和 foo. bam 的日志记录器都是 foo 的子级。而且,所有日志记录器都是根日志记录器的子级。
需要在多个 py 文件在记录日志时,有两种方法,一种是调用函数时候,通过参数方式,将主文件创建的 logger 传入到函数中;另一种是在文件中以模块名为 name 创建新的模块 logger,模块 logger 会将信息传递给 root logger 进行输出。第二种为常用用法,这种方式也可以兼容第三方库中的 logger 日志。
常用法的关键特性在于大部分代码都是简单地通过 getLogger (name) 创建一个模块级别的日志记录器,并使用该日志记录器来完成任何需要的日志记录。这样既简洁明了又能根据需要对下游代码进行细粒度的控制。记录到模块级日志记录器的消息会被转发给更高级别模块的日志记录器的处理器,一直到根日志记录器;因此这种方式被称为分级日志记录。
要使日志记录有用,需要对其进行配置:为每个日志记录器设置级别和目标,还可能改变特定模块的日志记录方式,通常是基于命令行参数或应用配置来实现。在大多数情况下,如上文所述,只有根日志记录器需要如此配置,因为所有在模块层级上的低级别日志记录器最终都会将消息转发给它的处理器。 basicConfig () 提供了一种配置根日志记录器的快捷方式,它可以处理多种应用场景。
注意永远不要直接实例化记录器,应当通过模块级别的函数 logging. getLogger (name) 。多次使用相同的名字调用 getLogger () 会一直返回相同的 Logger 对象的引用。