python中使用logging模块在控制台打印日志的同时也打印log文件,但发现控制台的信息会出现重复打印

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python中使用logging模块在控制台打印日志的同时也打印log文件,但发现控制台的信息会出现重复打印相关的知识,希望对你有一定的参考价值。

我使用python的logging模块,写了个函数logR("log info"), 发现调用logR在log文件中打印出来的日志很正常,但是在控制台打印出来的信息很不正常——第1次调用logR("msg 1")会打印1行msg1,正常;第2次调用logR('msg 2')就会打印2行msg 2,第3次会打印3行...

loggin模块需要进行很多封装才好用,你这种情况应该是初始化有问题,给你贴一段代码你自己照抄下来用用试试。

# -*- coding:UTF8 -*-
#

import os
import logging

class Logger(object):
    '''
    @summary:日志处理对象,对logging的封装
    '''
    def __init__(self,name = 'Logger'):

        self.logger = logging.getLogger( name )

        self.init_logger()

    def init_logger(self):

        self.logger.setLevel(logging.DEBUG)

        # 屏幕输出日志
        stream = logging.StreamHandler()
        stream.setLevel( logging.INFO )
        # 日志样式
        fm_stream = logging.Formatter("[\\033[1;%(colorcode)sm%(levelname)s\\033[0m   %(asctime)s   %(myfn)s:%(mylno)d:%(myfunc)s%(mymodule)s]   %(message)s", "%m-%d %H:%M:%S")
        stream.setFormatter( fm_stream )

        self.logger.addHandler( stream )

    def update_kwargs(self, kwargs, colorcode):
        try:
            fn, lno, func = self.logger.findCaller()
            fn = os.path.basename(fn)
        except Exception as ddd:
            fn, lno, func = "(unknown file)", 0, "(unknown function)"

        if not "extra" in kwargs:
            kwargs["extra"] = 

        kwargs["extra"]["myfn"] = fn
        kwargs["extra"]["mylno"] = lno
        kwargs["extra"]["myfunc"] = func
        kwargs["extra"]["colorcode"] = colorcode
        kwargs["extra"]["mymodule"] = ""

    def debug(self, msg, *args, **kwargs):
        self.update_kwargs(kwargs, "0")    # 原色
        self.logger.debug(msg, *args, **kwargs)

    def info(self, msg, *args, **kwargs):
        self.update_kwargs(kwargs, "32")   # 绿色
        self.logger.info(msg, *args, **kwargs)

    def warning(self, msg, *args, **kwargs):
        self.update_kwargs(kwargs, "33")   # 黄色
        self.logger.warning(msg, *args, **kwargs)

    def error(self, msg, *args, **kwargs):
        self.update_kwargs(kwargs, "31")   # 红色
        self.logger.error(msg, *args, **kwargs)

    def critical(self, msg, *args, **kwargs):
        self.update_kwargs(kwargs, "31")   # 红色
        self.logger.critical(msg, *args, **kwargs)


使用方法:

from logger import Logger


Logger().info('xxxxx')
Logger().warning('xxxxx')
Logger().error('xxxxx')

追问

但看这代码感觉跟我的操作出入不大啊。能了解一下初始化具体是出了什么问题吗?

参考技术A # 判断logger的句柄是否存在,存在则直接写日志,不存在则新建,如果不判断会造成日志重复记录问题
if not logger.handlers:

python中的logging模块学习

Python的logging模块

Logging的基本信息:

l  默认的情况下python的logging模块打印到控制台,只显示大于等于warning级别的日志

l  日志级别:critical > error > warning > info > debug > notset

Logging的基本组件:

1.   logger

l  logger是一个树形层级结构,输出信息之前都要获得一个logger

l  logger = logging.getLogger() 返回一个默认的logger也即rootLogger,并应用默认的日志级别,即只有日志等级大于等于warning级别的信息输出

l  也可以通过logger.setLevel(lel)指定最低的日志级别,可用的日志级别有:

l  logging.DEBUG,logging.INFO,Logging.ERROR,logging.CRITICAL;logger.debug(),logger.info().logger.warning(),logger.error(),logger.critical()

2.   handler

l  handler对象负责发送相关的信息到指定目的地

l  handler.setlevel(lel):指定日志级别,低于lel级别的日志将被忽略

l  handler.setFormatter():给handler选择一个Formatter

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

l  logging.FileHander 用于向一个文件输出日志信息

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

l  logging.handlers.TimeRotatingFileHandler和RotatingFileHandler类似,不过它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就自动创建新的日志文件

Formatter

l  formatter对象设置日志信息最后的规则,结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S

Filter

l  filter:限制只有满足过滤规则的日志才会输出

l  比如定义了filter = logging.Filter(‘jiyanjiao’),并将这个Filter添加到一个Handler上,则使用该handler的Logger中只有名字带’jiyanjiao’前缀的logger才能输出其日志

下面就来说一下具体的应用吧

l  需求是这样的:想打印自己的log,因为使用print每次都需要编辑替换觉得很麻烦,想让自己的程序更加正规些,也想区分不同级别log的颜色所以写下了如下的代码

import logging
import ctypes

\'\'\'
 定义颜色日志级别颜色变量:
 \'\'\'
FOREGROUND_WHITE = 0x0007
FOREGROUND_BLUE = 0x01
FOREGROUND_GREEN = 0x02
FOREGROUND_RED = 0x04
FOREGROUND_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN
STD_OUTPUT_HANDLE = -11
std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
def set_color(color, handle=std_out_handle):
    bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
    return bool

class mylogger(object):

    def __init__(self,name=\'mylogger\'):
        self.logger = logging.getLogger(name)
        self.init_logger()

    \'\'\'
    创建一个file_handler,用于写入日志文件
    再创建一个stream_handler,用于输出到控制台
    定义handler的输出格式formatter
        %(asctime)s   字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
        %(name)s      Logger的名字
        %(levelname)s  文本形式的日志级别
        %(message)s    用户输出的消息
    \'\'\'

    def init_logger(self):
        self.logger.setLevel(logging.DEBUG)
        file_handler = logging.FileHandler(\'D:/tmp/test.log\')
        stream_handler = logging.StreamHandler()

        formatter = logging.Formatter(\'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
        file_handler.setFormatter(formatter)
        stream_handler.setFormatter(formatter)

        self.logger.addHandler(file_handler)
        self.logger.addHandler(stream_handler)

    def debug(self,message,color=FOREGROUND_BLUE):
        set_color(color)
        self.logger.debug(message)
        set_color(FOREGROUND_WHITE)

    def info(self, message, color=FOREGROUND_GREEN):
        set_color(color)
        self.logger.info(message)
        set_color(FOREGROUND_WHITE)

    def warn(self,message,color=FOREGROUND_YELLOW):
        set_color(color)
        self.logger.warn(message)
        set_color(FOREGROUND_WHITE)

    def error(self, message,color=FOREGROUND_RED):
        set_color(color)
        self.logger.error(message)
        set_color(FOREGROUND_WHITE)

    def critical(self,message,color=FOREGROUND_RED):
        set_color(color)
        self.logger.critical(message)
        set_color(FOREGROUND_WHITE)

if __name__ == \'__main__\':
    mylogger = mylogger()
    mylogger.debug(\'这是debug信息\')
    mylogger.info(\'这是info信息\')
    mylogger.warn(\'这是warning\')
    mylogger.error(\'这是error信息\')
    mylogger.critical(\'这是critical信息\')

打印的结果:

那么可能有同学就有疑问了那么ctypes是什么

l  Ctypes是python的一个外部库,提供和c语言兼容的数据类型,可以很方便的调用C DLL中的函数

以上是关于python中使用logging模块在控制台打印日志的同时也打印log文件,但发现控制台的信息会出现重复打印的主要内容,如果未能解决你的问题,请参考以下文章

在 python 项目中如何记录日志

Python+Selenium进行UI自动化测试项目中,常用的小技巧4:日志打印,longging模块(控制台和文件同时输出)

python避坑指南02——logging模块日志重复打印问题

Python3之logging模块浅析

python中记录打印的log模块logging的用法实例

python中的logging模块学习