Python Logger的简单介绍以及在神经网络训练时的使用

0. 引言

我们在GitHub下载别人的代码时,总会发现logger这个包的使用,仔细观察后发现,logger代替了print,下文就是为了搞明白logger的具体用法和使用的场景。

1. logging模块的介绍

logging就是日志,一般用来记录程序在运行过程中发生的状况,在程序开发过程中添加日志模块能够帮助我们了解程序运行过程中发生了哪些事件。当然不是说所有的事件都是需要我们关注的,所以事件也有轻重之分。

logging可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比 print,具备如下优点:

  • 可以通过设置不同的日志等级,在 release 版本中只输出重要信息,而不必显示大量的调试信息;
  • print 将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据logging 则可以由开发者决定将信息输出到什么地方,以及怎么输出
  • print 相比,logging 是线程安全的。

线程安全:线程执行一段代码,不会产生不确定的结果,那这段代码就是线程安全的。
多线程的时候执行 print 应该是一行行打印,但是很多字符串打在了一起,为什么?
说明,print 函数被打断了,被线程切换打断了。
print 函数分两步

  1. 第一步打印字符串
  2. 第二步打印换行符,就在这之间,发生了线程的切换。

这说明 print 函数是线程不安全的。

2. 事件及其(event)的级别介绍

下面是事件的级别分类:

事件名称 说明 适用场景 Level 是否被输出到控制台
DEBUG 我们在进行debug时,想让某一个东西被输出 诊断问题时使用 10 不会
INFO 运行的该程序时打印的日志,目的是确认该程序是否如期进行 程序运行时正常的记录 20 不会
WARNING WARNING并不影响程序运行,但是出现了一些小的问题 部分程序没有如期运行 30
ERROR 某些程序不能执行特定的功能 该功能很重要,我们需要进行记录 40
CRITICAL 发生了严重的错误,程序无法运行 发生致命错误时的记录 50

虽然事件是有轻重缓急之分,但是应该有一个具体数值来衡量,这里使用[10, 20, 30, 40, 50]的数值来区分不同的日志类型。

  • logging默认的级别是WARNING,也就意味着只有级别大于等于的才会被看到
  • 跟踪日志的方式可以是①写入到文件中,也可以②直接输出到控制台

3. 日志输出级别调整 —— logging.basicConfig(**kwargs)

使用默认格式化程序创建 StreamHandler 并将其添加到根日志记录器中,从而完成日志系统的基本配置。如果没有为根日志程序定义处理程序,debug()info()warning()error()critical() 函数将自动调用 basicConfig()
如果根日志记录器已经为其配置了处理程序,则此函数不执行任何操作。

logging.basicConfig(**kwargs)支持以下关键字参数:

参数名 描述
filename 日志的保存文件,即不在控制台输出而是将日志输入到该文件中
filemode 该日志存储文件的打开模式,可选:①r(只读);②w(只写);③a(追加)。默认为a
format 日志的字符串格式
datefmt 使用time.strftime()所接收的指定日期/时间格式
style 如果指定了格式,则对格式化字符串使用此样本。%用于printf样式;{ 用于str.format()样式;$用于string样式。默认为%
level 记录的最低日志级别,低于该级别的就不记录了(等于该级别的还会记录)。默认为logging.WARNING

举个例子:

import logging  # 导入日志包


# 控制输出日志的等级
logging.basicConfig(level=logging.WARNING,
                   format="%(asctime)s %(filename)s %(levelname)s %(message)s",
                   datefmt="%a %d %b %Y %H:%M:%S")
"""
    format="%(asctime)s %(filename)s %(levelname)s %(message)s":表示输出日志的格式:时间 文件名 日志级别 具体的信息
    datefmt="%a %d %b %Y %H:%M:%S"):时间的格式
            a: 本地简化星期名称
            d: 月内中的一天(0-31)
            b: 本地简化的月份名称
            Y: 四位数的年份表示(000-9999)
            H: 24小时制小时数(0-23)
            M: 分钟数(00-59)
            S: 秒(00-59)
"""



logging.debug("[debug]Debug时使用的日志")
logging.info("[info]日常运行的日志")
logging.warning("[warning]记录警告!")
logging.error("[error]发生部分错误时的日志")
logging.critical("[critical]发生致命错误时的日志")


"""
	Fri 13 May 2022 09:38:36 432319022.py WARNING [warning]记录警告!
	Fri 13 May 2022 09:38:36 432319022.py ERROR [error]发生部分错误时的日志
	Fri 13 May 2022 09:38:36 432319022.py CRITICAL [critical]发生致命错误时的日志
"""

4. 跟踪日志的方法

跟踪日志的方式有两种:

  1. 写入到文件中
  2. 直接输出到控制台

接下来使用小例子对这两种方式进行说明。

4.1 输出到控制台

import logging  # 导入日志包


# 1. 跟踪日志的第一种方式 —— 输出到控制台
logging.debug("[debug] Debug时使用的日志")
logging.info("[info] 日常运行的日志")
logging.warning("[warning] 记录警告!")
logging.error("[error] 发生部分错误时的日志")
logging.critical("[critical] 发生致命错误时的日志")


"""
    WARNING:root:[warning] 记录警告!
    ERROR:root:[error] 发生部分错误时的日志
    CRITICAL:root:[critical] 发生致命错误时的日志
"""

可以看到,当不指定最低的日志等级,默认为logging.WARNING

4.2 输出到文件

需要输出到文件则首先需要修改logging的基础配置文件,如下:

logging.basicConfig(filename="存储文件的位置/文件名/格式", level=输出日志的最低级别)
  • 格式一般是.log
  • 输出日志的最低级别有:
    • logging.DEBUG
    • logging.INFO
    • logging.WARNING
    • logging.ERROR
    • logging.CRITICAL

例子1:最低输出日志的级别为logging.DEBUG

import logging  # 导入日志包


# 2. 跟踪日志的第一种方式 —— 输出到文件
logging.basicConfig(filename='./example.log', level=logging.DEBUG)
logging.debug("[debug] Debug时使用的日志")
logging.info("[info] 日常运行的日志")
logging.warning("[warning] 记录警告!")
logging.error("[error] 发生部分错误时的日志")
logging.critical("[critical] 发生致命错误时的日志")

此时控制台并没有输出,而是在当前文件夹下生成了一个example.log的文件,文件内容如下:

DEBUG:root:[debug] Debug时使用的日志
INFO:root:[info] 日常运行的日志
WARNING:root:[warning] 记录警告!
ERROR:root:[error] 发生部分错误时的日志
CRITICAL:root:[critical] 发生致命错误时的日志

可以看到,这个文件中保存了所有的日志信息。

例子2:最低输出日志的级别为logging.WARNING

import logging  # 导入日志包


# 2. 跟踪日志的第一种方式 —— 输出到文件
logging.basicConfig(filename='./example.log', level=logging.WARNING)
logging.debug("[debug] Debug时使用的日志")
logging.info("[info] 日常运行的日志")
logging.warning("[warning] 记录警告!")
logging.error("[error] 发生部分错误时的日志")
logging.critical("[critical] 发生致命错误时的日志")

example.log文件内容如下:

WARNING:root:[warning] 记录警告!
ERROR:root:[error] 发生部分错误时的日志
CRITICAL:root:[critical] 发生致命错误时的日志

这个日志中只保留等级≥WARNING的日志信息。

5. 自定义日志的记录内容

5.1 直接在logger.日志类型()中自定义

举个例子:

import logging

a = [1, 2, 3]

logger = logging.getLogger()
logger.setLevel(logging.WARNING)

logger.warning(f"此时a的值为: {
      
      a}")


"""
    此时a的值为: [1, 2, 3]
"""

5.2 通过设置format来统一日志的记录格式

import logging
import time

logging.basicConfig(filename="./logging信息.log", 
                    filemode="a",
                    level=logging.NOTSET,
                    format="%(asctime)s [%(filename)s]: [%(levelname)s] -> %(message)s",
                    datefmt="[%a %d %Y %H:%M:%S]"
                   )

a = [1, 2, 3]

logging.debug("这是一条debug信息")
logging.info(f"程序正常运行时的信息,此时a为: {
      
      a}")


"""
[Fri 13 2022 10:04:47] [1339390831.py]: [DEBUG] -> 这是一条debug信息
[Fri 13 2022 10:04:47] [1339390831.py]: [INFO] -> 程序正常运行时的信息,此时a为: [1, 2, 3]

"""

6. 神经网络训练时的使用

这里只是举个简单的小例子,根据实际代码进行修改。

import logging
import random
import time


# 定义logging输出的格式和内容
logging.basicConfig(level=logging.INFO,
                    format="%(asctime)s %(levelname)s %(message)s",
                    datefmt="[%a %d %Y %H:%M:%S]"
                   )

def net(input):
    return input * random.randint(10, 100) + random.randint(100, 200)

loss_function = lambda x: x/200

epochs = 30

for epoch in range(0, epochs):
    start = time.time()
    input = random.randint(1, 10)
    output = net(input)
    loss = loss_function(output)
    
    # 记录
    logging.info(f"\tEpoch: {
      
      epoch+1}/{
      
      epochs}\tcost: {
      
      time.time() - start:.4f}\tloss: {
      
      loss:.4f}\toutput: {
      
      output:.4f}")
    
    
"""
    [Fri 13 2022 10:19:34] INFO 	Epoch: 1/30	cost: 0.0000	loss: 3.0600	output: 612.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 2/30	cost: 0.0000	loss: 1.2100	output: 242.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 3/30	cost: 0.0000	loss: 3.9100	output: 782.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 4/30	cost: 0.0000	loss: 1.1200	output: 224.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 5/30	cost: 0.0000	loss: 2.9450	output: 589.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 6/30	cost: 0.0000	loss: 4.1850	output: 837.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 7/30	cost: 0.0000	loss: 0.8100	output: 162.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 8/30	cost: 0.0000	loss: 3.2900	output: 658.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 9/30	cost: 0.0000	loss: 5.0300	output: 1006.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 10/30	cost: 0.0000	loss: 1.2900	output: 258.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 11/30	cost: 0.0000	loss: 3.9050	output: 781.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 12/30	cost: 0.0000	loss: 2.3500	output: 470.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 13/30	cost: 0.0000	loss: 1.5350	output: 307.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 14/30	cost: 0.0000	loss: 0.8800	output: 176.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 15/30	cost: 0.0000	loss: 1.2850	output: 257.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 16/30	cost: 0.0000	loss: 1.0450	output: 209.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 17/30	cost: 0.0000	loss: 1.9250	output: 385.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 18/30	cost: 0.0000	loss: 2.2750	output: 455.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 19/30	cost: 0.0000	loss: 2.7200	output: 544.0000
    [Fri 13 2022 10:19:34] INFO 	Epoch: 20/30	cost: 0.0000	loss: 1.9450	output: 389.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 21/30	cost: 0.0000	loss: 1.1500	output: 230.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 22/30	cost: 0.0000	loss: 2.4850	output: 497.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 23/30	cost: 0.0000	loss: 1.3800	output: 276.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 24/30	cost: 0.0000	loss: 0.9550	output: 191.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 25/30	cost: 0.0000	loss: 1.0350	output: 207.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 26/30	cost: 0.0000	loss: 3.1400	output: 628.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 27/30	cost: 0.0000	loss: 2.4550	output: 491.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 28/30	cost: 0.0000	loss: 1.0750	output: 215.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 29/30	cost: 0.0000	loss: 4.5150	output: 903.0000
    [Fri 13 2022 10:19:35] INFO 	Epoch: 30/30	cost: 0.0000	loss: 4.5950	output: 919.0000
"""

参考

  1. https://www.jb51.net/article/126681.htm
  2. https://blog.csdn.net/colinlee19860724/article/details/90965100

猜你喜欢

转载自blog.csdn.net/weixin_44878336/article/details/124730453
今日推荐