python+logging

日誌按照下面四個層次來完成日誌的功能api

1  Logger暴露出來給應用使用的接口app

2  Handlers是發送日誌記錄(由logger建立的)到合適的目的地,包括文件,屏幕,email...scrapy

3  Filters 是提供一個過濾的機制,決定哪些日誌能夠留下this

4  Formatters是輸出日誌的格式url

 

建立格式:spa

logger = logging.getLogger('apps') # 建立一個新的apps 的logger

logger.setLevel(logging.DEBUG)  # 由於它是會默認傳播到祖先logger

logger.propagate = False  # 默認StreamHandler那裏, 也就是不會打印在頁面上

apps_handler = logging.FileHandler(filename="apps.log")  # 添加handler, 決定日誌落地到哪裏,能夠多個

apps_formatter=logging.Formatter('%(asctime)s:%(name)s:%(levelname)s:%(message)s'  # 輸出日誌的格式

apps_handler.setFormatter(apps_formatter)  # 裝載上

logger.addHandler(apps_handler)  # 裝載實例化logger上

# 日誌會打印到apps.log, 而且不會輸出到屏幕(若是logger.propagate=True就會)

 

繼承;日誌

# 定義一個新的logger

child_logger = logging.getLogger('apps.owan')

# 由於這個child_logger 是apps.owan, 它是繼承了apps這個logger

# 這個child_logger.propagate 默認是True

# 因此仍是會傳到它的祖先logger 也就是apps

child_logger.info('haha')

# 因此這個info 是會傳播到apps 因此apps.log會出現這個日誌。

# 這裏充分說明logger的繼承關係

 

定義Log兩種方法

第一種:就是實例化logger = logging.logger 而後手動給logger添加addHandler, addFilter, handler.setFormatter 添加格式,這樣的形式來獲取logger。。。。。code

import logging

# 沒有建立logger, 默認是root logger, 直接打印在屏幕

logging.basicConfig(level=logging.DEBUG,format='%(asctime)s:%(name)s:%(levelname)s:%(message)s')                                                                                             

logger = logging.getLogger('apps')

apps_handler = logging.FileHandler(filename="apps.log")

logger.addHandler(apps_handler)

logger.setLevel(logging.DEBUG)

logger.info('shis')

 

第二種:就是使用 logging.config.dictConfig 來從配置文件生成loggerorm

logging.config.dictConfig(log_config.PATTERN)

# 沒有定義的logger

tool_logger = logging.getLogger('ToolApi')

# 因爲沒有定義,會冒泡到root logger

tool_logger.info('----------------')

# 定義過的api logger

api_logger = logging.getLogger('API')

# 定義過了,因此api本身的handler會處理,同時會冒泡到root logger處理

api_logger.error('fuck !')

 

配置文件:blog

PATTERN = {

    'version': 1,

    'formatters': {

        'normal': {

            'format': '%(name)s %(asctime)s %(levelname)s %(message)s',

            'datefmt': '%Y-%m-%d %H:%M:%S'

        },

        'raw': {

            'format': '%(message)s',

        },

    },

    'handlers': {

        'console': {

            'class': 'logging.StreamHandler',

            'stream': 'ext://sys.stdout',

            'formatter': 'normal',

        },

        'root': {

            'class': 'logging.handlers.WatchedFileHandler',

            'formatter': 'normal',

            'filename': RUNTIME_HOME + '/var/log/root.log',

            'mode': 'a',

            'level': 'INFO',

        },

        'extapi': {

            'class': 'logging.handlers.WatchedFileHandler',

            'formatter': 'normal',

            'filename': RUNTIME_HOME + '/var/log/ext_api.log',

            'mode': 'a',

            'level': 'DEBUG',

        },

        'api': {

            'class': 'logging.handlers.WatchedFileHandler',

            'formatter': 'normal',

            'filename': RUNTIME_HOME + '/var/log/api.log',

            'mode': 'a',

            'level': 'DEBUG',

        },

    },

    'loggers': {

        'API': {'level': 'DEBUG',

                'handlers': ['api'],

                },

        'EXTAPI': {'level': 'DEBUG',

                   'handlers': ['extapi'],

                   },

        'requests.packages.urllib3.connectionpool': {'level': 'ERROR'},

    },

    'root': {

        'handlers': ['root',],

        'level': 'INFO',

    }

}

 

例子:

import logging

import os

from douban_scrapy import settings

from logging.handlers import RotatingFileHandler

from logging import StreamHandler

 

# 直接繼承logging.Logger 那麼就是說這個類就是一個Logger, 有了Logger全部方法

# 只是在類裏面添加一些內部方法,讓logger 封裝addhandler, setformatter等方法

class LogHandler(logging.Logger):

    # 單例模式

    _instance = None

    def __new__(cls, *args, **kwargs):

        if not cls._instance:

            # 一開始竟然用了 cls()來實例化 致使無限次調用

            # cls._instance = cls(*args, **kwargs)

            cls._instance = object.__new__(cls, *args, **kwargs)

        return cls._instance

 

    def __init__(self, name, level=logging.DEBUG, to_stream=True, to_file=True):

        self.name = name

        self.level = level

        self.formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')

        # 錯誤的, 繼承了logger 自己就是logger 不用再self.logger=xxx 這樣變成了一個新的變量

        #self.logger = logging.Logger(name=name, level=level)

        super(LogHandler, self).__init__(name=name, level=level)

 

        # 寫文件

        if to_file:

            self.__setFileHandler__()

 

        # 寫標準輸出

        if to_stream:

            self.__setSteamHandler__()

 

    def __setSteamHandler__(self):

        stream_handler = StreamHandler()

        stream_handler.setFormatter(self.formatter)

        self.addHandler(stream_handler)

 

    def __setFileHandler__(self):

        log_path = os.path.join(settings.LOG_DIR, self.name +'.log')

        handler = RotatingFileHandler(log_path, maxBytes=1024, backupCount=5)

        handler.setFormatter(self.formatter)

        self.addHandler(handler)

 
 

if __name__ == '__main__':

    logger = LogHandler('scrapy')

    logger2 = LogHandler('scrapy')

    print logger, logger2

logger.info('haha')

 

2:-----------------------------------------------------------------------------------------------------------------------2

import os

import logging

from logging.handlers import TimedRotatingFileHandler

 

# 日誌級別

CRITICAL = 50

FATAL = CRITICAL

ERROR = 40

WARNING = 30

WARN = WARNING

INFO = 20

DEBUG = 10

NOTSET = 0

 

CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))

ROOT_PATH = os.path.join(CURRENT_PATH, os.pardir)

LOG_PATH = os.path.join(ROOT_PATH, 'log')

 

 

class LogHandler(logging.Logger):

    """

    LogHandler

    """

 

    def __init__(self, name, level=DEBUG, stream=True, file=True):

        self.name = name

        self.level = level

        logging.Logger.__init__(self, self.name, level=level)

        if stream:

            self.__setStreamHandler__()

        if file:

            self.__setFileHandler__()

 

    def __setFileHandler__(self, level=None):

        """

        set file handler

        :param level:

        :return:

        """

        file_name = os.path.join(LOG_PATH, '{name}.log'.format(name=self.name))

        # 設置日誌回滾, 保存在log目錄, 一天保存一個文件, 保留15天

        file_handler = TimedRotatingFileHandler(filename=file_name, when='D', interval=1, backupCount=15)

        file_handler.suffix = '%Y%m%d.log'

        if not level:

            file_handler.setLevel(self.level)

        else:

            file_handler.setLevel(level)

        formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')

 

        file_handler.setFormatter(formatter)

        self.file_handler = file_handler

        self.addHandler(file_handler)

 

    def __setStreamHandler__(self, level=None):

        """

        set stream handler

        :param level:

        :return:

        """

        stream_handler = logging.StreamHandler()

        formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')

        stream_handler.setFormatter(formatter)

        if not level:

            stream_handler.setLevel(self.level)

        else:

            stream_handler.setLevel(level)

        self.addHandler(stream_handler)

 

    def resetName(self, name):

        """

        reset name

        :param name:

        :return:

        """

        self.name = name

        self.removeHandler(self.file_handler)

        self.__setFileHandler__()

 

if __name__ == '__main__':

    log = LogHandler('test')

    log.info('this is a test msg')
相關文章
相關標籤/搜索