欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Python 的常用模块 5

最编程 2024-07-12 11:47:33
...

一、日志模块,logging模块

1)logging模块简单使用,屏幕输出。默认级别30

import logging

logging.debug('debug...')   # 10
logging.info('info....')    #20
logging.warning('可能着火...') #30
logging.error('着火啦快跑') # 40
logging.critical('火越烧越大') #50
View Code

2)控制日志输出到文件,但屏幕显示信息会消失。注意,存入文件时是以gbk,所以打开时,也要指定gbk格式

import logging

# 控制日志输出
logging.basicConfig(
filename='access.log',   # 记录在当前目录,生成文件
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
        # 时间       日志的名,如debug,error    级别     模块          # 接收的信息
datefmt='%Y-%m-%d %H:%M:%S %p', # 时间
level=20,
)
logging.debug('debug...')   # 10
logging.info('info....')    #20
logging.warning('可能着火...') #30
logging.error('着火啦快跑') # 40
logging.critical('火越烧越大') #50
View Code

 3)日志模块调用原理

import logging

#logger对象:用来产生日志
logger1=logging.getLogger('银行业务相关') # 日志名是用告诉我们所记录的日志到底是属于哪一类业务相关的信息

#filter对象:过滤日志

#handler对象:控制日志的去向: 文件 或 终端
fh1=logging.FileHandler('a1.log',encoding='utf-8')
fh2=logging.FileHandler('a2.log',encoding='utf-8')
ch=logging.StreamHandler() #代表的就是终端

# 建立logger对象与handler对象的绑定关系
logger1.addHandler(fh1)
logger1.addHandler(fh2)
logger1.addHandler(ch)

#formmatter对象:定制日志的格式
formatter1=logging.Formatter(
    fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p'
)

formatter2=logging.Formatter(
    fmt='%(asctime)s ===> %(message)s',
)

# 为handler对象绑定日志格式
fh1.setFormatter(formatter1)
fh2.setFormatter(formatter2)
ch.setFormatter(formatter2)

#设置日志级别:两层关卡,第一次是logger,第二层是handler,只有两层都放行,最终日志才会打印
# logger1.setLevel(50)
# fh1.setLevel(10)
# fh2.setLevel(10)
# ch.setLevel(10)

logger1.setLevel(10)
fh1.setLevel(10)
fh2.setLevel(10)
ch.setLevel(10)

# 调用logger对象产生日志
logger1.debug('这是一条debug日志')
View Code

 4)引用字典加载日志模块配置

日志配置文件,setting_log.py

import logging

# 定义日志文件的保存路径
logfile_path=r'D:\oldboyedu\manth-02\day-02\a1.log'

# 定义日志格式
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'


# log配置字典
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
    },
    'filters': {},
    'handlers': {
        #打印到终端的日志
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到终端
            'formatter': 'simple'
        },
        #打印到文件的日志,
        'default': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',  # 保存到文件  # logging.handlers.RotatingFileHandler
            'formatter': 'standard',
            'filename': logfile_path,  # 日志文件
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },

    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        'logger1': {
            'handlers': ['default', 'console'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}
setting_log

升级修改的配置文件,增加日志轮转的功能

        'default': {
            'level': 'DEBUG',
           # 'class': 'logging.FileHandler',  # 保存到文件  # logging.handlers.RotatingFileHandler
            'class': 'logging.handlers.RotatingFileHandler',
            'formatter': 'standard',
            'filename': logfile_path,  # 日志文件
            'maxBytes': 1024*1024*5,     # 日志文件大小 5M
            'backupCount': 5,
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
View Code

功能调用日志模块配置文件

import logging.config
from setting_log import LOGGING_DIC     # 导入日志的配置文件

logging.config.dictConfig(LOGGING_DIC)
logging1 = logging.getLogger('logger1')
logging1.debug('调试日志')
View Code

 5)升级版,新增配置日志文件,如boss的日志

import logging

# 定义日志文件的保存路径
logfile_path=r'D:\oldboyedu\manth-02\day-02\a1.log'
boss_logfile_path=r'D:\oldboyedu\manth-02\day-02\a2.log'

# 定义日志格式
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

id_simple_format = '[%(asctime)s] %(message)s'  # 给boss的日志,简单明了的日志

# log配置字典
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
        'id_simple': {
            'format': id_simple_format
        }
    },
    'filters': {},
    'handlers': {
        #打印到终端的日志
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到终端
            'formatter': 'simple'
        },
        #打印到文件的日志,
        'default': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',  # 保存到文件  # logging.handlers.RotatingFileHandler
            'formatter': 'standard',
            'filename': logfile_path,  # 日志文件
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
        # 打印给boss的日志
        'boss': {
            'level': 'ERROR',
            'class': 'logging.FileHandler',  # 保存到文件  # logging.handlers.RotatingFileHandler
            'formatter': 'id_simple',
            'filename': boss_logfile_path,  # 日志文件
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        'logger1': {
            'handlers': ['default', 'console','boss'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}
setting_log2

 6)函数调用配置文件输出日志

def get_logger(logger_name):
    # 获取输入日志的信息
    logging.config.dictConfig(settings.LOGGING_DIC)  # 导入上面定义的settings配置
    logger=logging.getLogger(logger_name)
    return logger
    
logger=get_logger('logger1')
def register():
    logger.info('用户%s注册成功' %user)
    
def info():
    logger.info('用户%s登录成功' %user)
View Code

7)可实现任意log对象的配置,字典的key为空即可

    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        '': {
            'handlers': ['default', 'console'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
任意log对象配置

 8)扩展,log的日志格式

可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。 
datefmt:指定日期时间格式。 
level:设置rootlogger(后边会讲解具体概念)的日志级别 
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。



#格式
%(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:用户输出的消息
日志格式扩展

9)引入其他模块的日志输出

import logging
from logging.handlers import TimedRotatingFileHandler
class LogConfig(object):
    #APP_LOG = '/opt/SRE/log/a.log'
    APP_LOG = './log/a.log'
    LOG_LEVEL = 'INFO'
    LOG_DATEFMT = '%Y-%m-%d %H:%M:%S'
    LOG_FORMAT = '[%(asctime)s] [%(process)d] [%(levelname)s] - %(module)s.%(funcName)s ' \
                 '(%(filename)s:%(lineno)d) - %(message)s'
    LOG_WHEN = 'D'
    LOG_INTERVAL = 1
    LOG_ROTATE_BACKUP_COUNT = 30

class Logger(object):
    def __init__(self):
        self.log_format = logging.Formatter(LogConfig.LOG_FORMAT)
        self.logger = logging.getLogger()

    def init(self):
        self.set_handler()
        self.set_loglevel()

    def set_handler(self):
        level = logging.getLevelName(LogConfig.LOG_LEVEL)

        if LogConfig.APP_LOG == '':
            # No APP_LOG print colorful log to console
            pass
            # coloredlogs.install(
            #     level=level,
            #     fmt=LogConfig.LOG_FORMAT,
            #     datefmt=LogConfig.LOG_DATEFMT,
            # )
        else:
            file_handler = TimedRotatingFileHandler(
                filename=LogConfig.APP_LOG,
                when=LogConfig.LOG_WHEN,
                interval=LogConfig.LOG_INTERVAL,
                backupCount=LogConfig.LOG_ROTATE_BACKUP_COUNT,
                encoding='utf-8'
            )

            file_handler.setFormatter(self.log_format)
            self.logger.addHandler(file_handler)

            # print to console
            # console_handler = logging.StreamHandler()
            # console_handler.setFormatter(self.log_format)
            # self.logger.addHandler(console_handler)

    def set_loglevel(self):
        log_level = LogConfig.LOG_LEVEL
        assert log_level in ['DEBUG', 'INFO', 'WARNING', 'ERROR'], "log level not correct"
        self.logger.setLevel(getattr(logging, log_level))

if __name__ == '__main__':
    loger = Logger()
    loger.init()

10)loguru模块的使用: pip3 install loguru

import os
from loguru import logger
dir_log = "logs"
path_log = os.path.join(dir_log, '日志文件.log')

logger.add(path_log, rotation='0:00', enqueue=True, serialize=False, encoding="utf-8", retention="10 days")
logger.debug("服务器重启!")

参数意义

logger . add ( "file_1.log" , rotation = "500 MB" )      # 文件过大就会重新生成一个文件
logger . add ( "file_2.log" , rotation = "12:00" )      # 每天12点创建新文件
logger . add ( "file_3.log" , rotation = "1 week" )      # 文件时间过长就会创建新文件
logger . add ( "file_X.log" , retention = "10 days" )    # 一段时间后会清空
logger . add ( "file_Y.log" , compression = "zip" )      # 保存zip格式

logger . add ( "somefile.log" , enqueue = True )    # 异步写入
logger . add ( "somefile.log" , serialize = True )    # 序列化为json
logger . add ( "file.log" , format = "{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}" )   时间格式化

使用多文件处理

 

二、跨平台序列化存储数据。json和pickle

1)序列化的概念,意义

01 什么是序列化
    序列化:把内存中的数据转成一种中间格式(json/pickle),然后存放到硬盘中,永久保存
    反序列化:从文件中读出(json/pickle)格式,然后返解成python的数据类型

02 为什么要序列化
    1、数据结构持久化

    2、跨平台数据交互

03 如何进行序列化,反序列化
    json:
        缺点:
            只能支持部分python的数据类型
        优点:
            所有的语言都支持json格式

        应用:
            如果需要考虑跨平台性,则需要用json格式
    pickle
        缺点:
            只有python支持pickle格式
        优点:
            pickle能够支持所有的python数据类型

        应用:
            如果不需要考虑跨平台性,则可以用pickle格式
View Code

2)json支持转换python格式的类型

 

 

3)json序列化模块的使用

import json

# dic={'name':'egon','age':18,'is_beautiful':True}

# #序列化
# res=json.dumps(dic) # 强调,json格式不识别单引号
# # print(res,type(res))
# with open('user.json','w',encoding='utf-8') as f:
#     f.write(res)

# 反序列化
# with open('user.json','r',encoding='utf-8') as f:
#     res=f.read()

# dic=json.loads(res)
# print(dic['name'])

# 强调,json格式不识别单引号
# with open('user1.json','r',encoding='utf-8') as f:
#     res=f.read()
#
# dic=json.loads(res)
# print(dic['x'])


# #序列化
# dic={'name':'egon','age':18,'is_beautiful':True}
#
# with open('user2.json','w',encoding='utf-8') as f:
#     json.dump(dic,f)

# 反序列化
with open('user.json','r',encoding='utf-8') as f:
    dic=json.load(f)

    print(dic['name'])
json的使用

4)pickle用法和json一模一样