4 python日志模块

教程 阿布都的都 ⋅ 于 2023-01-07 18:34:36 ⋅ 981 阅读

13 python程序的命名规则

1)单词首字母大写,驼峰规则

类名

2)小写字母,单词之间用_分割

模块名、包名、变量名、函数名、方法名

3)大写字母,单词之间用_分割

常量名

4)以_开头(2个下划线),但不以\_结尾

私有变量名、私有方法名(类外不可访问)

5)__开头,__结尾

开头,结尾,一般为python的自有变量,不要以这种方式命名

__doc__

__class__

注意:

_单下划线开头:

​ 弱“内部使用”标识,如:”from hainiu import *”,将不导入所有以下划线开头的对象,包括包、模块、成员;

单下划线结尾_:

​ 只是为了避免与python关键字的命名冲突;

__双下划线开头:

​ 模块内的成员,表示私有成员,外部无法直接调用;

​ 包和模块:模块应该使用尽可能短的、全小写命名,可以在模块命名时使用下划线以增强可读性。同样包的命名也应该是这样的;

14 Python logging 模块应用

​ logging 模块就好比 java 的 log4j,用来生成指定格式日志。

​ 默认情况下python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET)。

​ 如果不设置logger 名称,默认是root logger。

import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
#---------输出---------------------------------
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

​ 开发程序,需要把日志输出到控制台或输出到文件,需要先创建logger,然后再配置。

import logging
# 创建一个logger
logger = logging.getLogger('mylogger')
#设置logger的日志级别
logger.setLevel(logging.DEBUG)

# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')
#可以为每个handler设置不同的日志级别,但不要小于logger设置的日志级别,否则失效
fh.setLevel(logging.DEBUG)

# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

# 定义handler的输出格式,也就是日志的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)
# 记录一条日志
logger.info('this is test logger info')  
#---------输出---------------------------------
2018-12-23 18:24:30,992 - mylogger - INFO - this is test logger info

file

其中:

logger:

1)创建多个相同名称的logger,其实只创建了一个logger实例。

2)可以设置logger级别的日志级别,logger下的每个handler 可以设置各自的日志级别,但不要小于logger设置的日志级别,否则失效。

handler:

1)Handler对象负责发送相关的信息到指定目的地,有两个Handler方法:

Handler.setLevel(lel):指定日志级别,低于lel级别的日志将被忽略;

Handler.setFormatter():给这个handler选择一个Formatter;

2)handler有很多种,先介绍下面几种:

logging.StreamHandler:可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息;

logging.FileHandler:用于向一个文件输出日志信息;

logging.handlers.RotatingFileHandler:类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出;

logging.handlers.TimedRotatingFileHandler: 通过间隔一定时间就自动创建新的日志文件;

3)TimedRotatingFileHandler的构造函数定义

​ TimedRotatingFileHandler(filename [,when [,interval [,backupCount]]])

filename:是输出日志文件名的前缀

when:是一个字符串的定义如下:

​ “S”: Seconds

​ “M”: Minutes

​ “H”: Hours

​ “D”: Days

​ “W”: Week day (0=Monday)

​ “midnight”: Roll over at midnight

interval: 是指等待多少个单位when的时间后,Logger会自动重建文件,默认是1,当然,这个文件的创建取决于filename+suffix,若这个文件跟之前的文件有重名,则会自动覆盖掉以前的文件,所以有些情况suffix要定义的不能因为when而重复。

backupCount: 是保留日志个数。默认的0是不会自动删除掉日志。若设10,则在文件的创建过程中,会判断是否有超过这个10,若超过,则会从最先创建的开始删除。

​ 除了上述参数之外,TimedRotatingFileHandler还有两个比较重要的成员变量,它们分别是 suffix 和 extMatch 。

suffix 是指日志文件名的后缀,suffix中通常带有格式化的时间字符串,filename和suffix由“.”连接构成文件名(例如:filename=“runtime”, suffix=“%Y-%m-%d.log”,生成的文件名为runtime.2015-07-06.log)。

extMatch 是一个编译好的正则表达式,用于匹配日志文件名的后缀,它必须和suffix是匹配的,如果suffix和extMatch匹配不上的话,过期的日志是不会被删除的。比如,suffix=“%Y-%m-%d.log”, extMatch的只应该是re.compile(r”^\d{4}-\d{2}-\d{2}.log$”)。

​ 默认情况下,在TimedRotatingFileHandler对象初始化时,suffxi和extMatch会根据when的值进行初始化:

‘S’:        suffix=”%Y-%m-%d_%H-%M-%S”, extMatch=r”\^d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}”; 
‘M’:        suffix=”%Y-%m-%d_%H-%M”,    extMatch=r”^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}”; 
‘H’:        suffix=”%Y-%m-%d_%H”,       extMatch=r”^\d{4}-\d{2}-\d{2}_\d{2}”; 
‘D’:        suffxi=”%Y-%m-%d”,          extMatch=r”^\d{4}-\d{2}-\d{2}”; 
‘MIDNIGHT’: ”%Y-%m-%d”,                 extMatch=r”^\d{4}-\d{2}-\d{2}”; 
‘W’:        ”%Y-%m-%d”,                 extMatch=r”^\d{4}-\d{2}-\d{2}”; 

​ 如果对日志文件名没有特殊要求的话,可以不用设置suffix和extMatch,如果需要,一定要让它们匹配上。

Formatter:

​ 指定输出的格式和内容,format可以输出很多有用信息;

​ format参数中可能用到的格式化串:

%(name)s Logger的名字

%(levelno)s 数字形式的日志级别

%(levelname)s 文本形式的日志级别

%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有

%(filename)s 调用日志输出函数的模块的文件名

%(module)s 调用日志输出函数的模块名

%(funcName)s 调用日志输出函数的函数名

%(lineno)d 调用日志输出函数的语句所在的代码行

%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示

%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数

%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒

%(thread)d 线程ID。可能没有

%(threadName)s 线程名。可能没有

%(process)d 进程ID。可能没有

​ %(message)s用户输出的消息

按秒滚动日志 + 保留10个日志文件:

代码配置:

file

测试代码:

if __name__ == '__main__':
    import time
    while True:
        b = LogUtil().get_base_logger()
        b.info("111")
        b.error("222")
        try:
            1/0
        except:
            b.exception()
        time.sleep(1)

效果:

file

测试完上面的把配置改成按天滚动文件

file

LogUtil 的应用

#-*- encoding: utf-8 -*-
'''
log_util_demo.py
Created on 21-9-11 上午10:21
Copyright (c) 21-9-11, 海牛学院版权所有.
@author: 野牛
'''
from commons.util.log_util import LogUtil
logger1 = LogUtil().get_logger("logname", "filename")
logger2 = LogUtil().get_logger("logname", "filename")
# 测试单例模式
print(logger1 is logger2)
logger1.info("打印info信息")
logger1.error("打印info信息")
try:
    1/0
except Exception as e:
    logger1.exception(e)

注意:如果日志目录不存在,报错

file

单例设计模式:

​ 单例对象的类必须保证只有一个实例存在。

​ 对单例的实现可以分为两大类

​ 懒汉式:指全局的单例实例在第一次被使用时构建。
​ 饿汉式:指全局的单例实例在类装载时构建。

懒汉式代码:

public class SingleTest2 {
    public static void main(String[] args) {
        System.out.println(Singleton2.getInstance());
        System.out.println(Singleton2.getInstance());
    }
}

// 懒汉式
// 优点:只有用到了该对象,才会创建对象
// 缺点:线程不安全(在多线程下创建的不是一个对象)
class Singleton2 {
    private static Singleton2 instance = null;
    // 私有构造
    private Singleton2(){}
    // 公有get,在get时才创建
    public static Singleton2 getInstance(){
        if(instance == null){
            instance = new Singleton2();
        }
        return instance;
    }
}

饿汉式代码:

public class SingleTest1 {
    public static void main(String[] args) {
        System.out.println(Singleton1.getInstance());
        System.out.println(Singleton1.getInstance());
        System.out.println(Singleton1.getInstance());
    }
}
// 饿汉式
// 优点:可以保证线程安全(在多线程下也是一个对象)
// 缺点:由于类初始化时已经创建对象,不能保证在实际使用过程中配合的数据能提前生成
class Singleton1 {
    // 类初始化时已经创建对象
    private static Singleton1 INSTANCE = new Singleton1();
    // 私有构造器
    private Singleton1(){}
    // 公有get方法
    public static Singleton1 getInstance(){
        return INSTANCE;
    }
}

推荐的代码:

public class SingleTest3 {
    public static void main(String[] args) {
        System.out.println(Singleton3.getInstance());
        System.out.println(Singleton3.getInstance());
        System.out.println(Singleton3.getInstance());

    }
}

// 静态内部类实现单例
// 优点:只有用到的时候才加载,线程安全(推荐)
class Singleton3 {
    // 私有静态内部类,内部实现恶汉单例
    private static class SingletonHolder {
        private static final Singleton3 INSTANCE = new Singleton3();

    }
    // 私有构造
    private Singleton3(){}
    // 公有get,当调用该方法时,内部类才会加载,有且只加载一次
    public static final Singleton3 getInstance() {

        return SingletonHolder.INSTANCE;

    }

}
版权声明:原创作品,允许转载,转载时务必以超链接的形式表明出处和作者信息。否则将追究法律责任。来自海汼部落-阿布都的都,http://hainiubl.com/topics/76122
成为第一个点赞的人吧 :bowtie:
回复数量: 0
    暂无评论~~
    • 请注意单词拼写,以及中英文排版,参考此页
    • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
    • 支持表情,可用Emoji的自动补全, 在输入的时候只需要 ":" 就可以自动提示了 :metal: :point_right: 表情列表 :star: :sparkles:
    • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif,教程
    • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
    Ctrl+Enter