python 構建自己的log系統


python的logging模塊提供了記錄程序運行情況的日志功能,類似於Apache的log4j,很好很強大,這里我們就來看一下Python中內置的日志模塊logging用法詳解

logging模塊簡介

Python的logging模塊提供了通用的日志系統,可以方便第三方模塊或者是應用使用。這個模塊提供不同的日志級別,並可以采用不同的方式記錄日志,比如文件,HTTP GET/POST,SMTP,Socket等,甚至可以自己實現具體的日志記錄方式。
logging模塊與log4j的機制是一樣的,只是具體的實現細節不同。模塊提供logger,handler,filter,formatter。

  • logger:提供日志接口,供應用代碼使用。logger最長用的操作有兩類:配置和發送日志消息。可以通過logging.getLogger(name)獲取logger對象,如果不指定name則返回root對象,多次使用相同的name調用getLogger方法返回同一個logger對象。
  • handler:將日志記錄(log record)發送到合適的目的地(destination),比如文件,socket等。一個logger對象可以通過addHandler方法添加0到多個handler,每個handler又可以定義不同日志級別,以實現日志分級過濾顯示。
  •  filter:提供一種優雅的方式決定一個日志記錄是否發送到handler。
  •  formatter:指定日志記錄輸出的具體格式。formatter的構造方法需要兩個參數:消息的格式字符串和日期字符串,這兩個參數都是可選的。

與log4j類似,logger,handler和日志消息的調用可以有具體的日志級別(Level),只有在日志消息的級別大於logger和handler的級別。

logging用法解析

1. 初始化 logger = logging.getLogger("endlesscode"),getLogger()方法后面最好加上所要日志記錄的模塊名字,后面的日志格式中的%(name)s 對應的是這里的模塊名字
2. 設置級別 logger.setLevel(logging.DEBUG),Logging中有NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL這幾種級別,日志會記錄設置級別以上的日志
3. Handler,常用的是StreamHandler和FileHandler,windows下你可以簡單理解為一個是console和文件日志,一個打印在CMD窗口上,一個記錄在一個文件上
4. formatter,定義了最終log信息的順序,結構和內容,我喜歡用這樣的格式 '[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S',
  %(name)s Logger的名字
  %(levelname)s 文本形式的日志級別
  %(message)s 用戶輸出的消息
  %(asctime)s 字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號后面的是毫秒
  %(levelno)s 數字形式的日志級別
  %(pathname)s 調用日志輸出函數的模塊的完整路徑名,可能沒有
  %(filename)s 調用日志輸出函數的模塊的文件名
  %(module)s  調用日志輸出函數的模塊名
  %(funcName)s 調用日志輸出函數的函數名
  %(lineno)d 調用日志輸出函數的語句所在的代碼行
  %(created)f 當前時間,用UNIX標准的表示時間的浮 點數表示
  %(relativeCreated)d 輸出日志信息時的,自Logger創建以 來的毫秒數
  %(thread)d 線程ID。可能沒有
  %(threadName)s 線程名。可能沒有
  %(process)d 進程ID。可能沒有
5. 記錄 使用object.debug(message)來記錄日志

6. logging是線程安全的

簡單示例如下:

  

 1 import logging
 2 logger = logging.getLogger("simple_example")
 3 logger.setLevel(logging.DEBUG)
 4 # 建立一個filehandler來把日志記錄在文件里,級別為debug以上
 5 fh = logging.FileHandler("spam.log")
 6 fh.setLevel(logging.DEBUG)
 7 # 建立一個streamhandler來把日志打在CMD窗口上,級別為error以上
 8 ch = logging.StreamHandler()
 9 ch.setLevel(logging.ERROR)
10 # 設置日志格式
11 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
12 ch.setFormatter(formatter)
13 fh.setFormatter(formatter)
14 #將相應的handler添加在logger對象中
15 logger.addHandler(ch)
16 logger.addHandler(fh)
17 # 開始打日志
18 logger.debug("debug message")
19 logger.info("info message")
20 logger.warn("warn message")
21 logger.error("error message")
22 logger.critical("critical message")

當你的項目較大時,你就需要一個比較方便規范的使用的方式,建議將你的kog系統設計為class方式,這樣就可以方便使用

 1 #! /usr/bin/env python
 2 #coding=gbk
 3 import logging,os
 4  
 5 class Logger:
 6  def __init__(self, path,clevel = logging.DEBUG,Flevel = logging.DEBUG):
 7   self.logger = logging.getLogger(path)
 8   self.logger.setLevel(logging.DEBUG)
 9   fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
10   #設置CMD日志
11   sh = logging.StreamHandler()
12   sh.setFormatter(fmt)
13   sh.setLevel(clevel)
14   #設置文件日志
15   fh = logging.FileHandler(path)
16   fh.setFormatter(fmt)
17   fh.setLevel(Flevel)
18   self.logger.addHandler(sh)
19   self.logger.addHandler(fh)
20  
21  def debug(self,message):
22   self.logger.debug(message)
23  
24  def info(self,message):
25   self.logger.info(message)
26  
27  def war(self,message):
28   self.logger.warn(message)
29  
30  def error(self,message):
31   self.logger.error(message)
32  
33  def cri(self,message):
34   self.logger.critical(message)
35  
36 if __name__ =='__main__':
37  logyyx = Logger('yyx.log',logging.ERROR,logging.DEBUG)
38  logyyx.debug('一個debug信息')
39  logyyx.info('一個info信息')
40  logyyx.war('一個warning信息')
41  logyyx.error('一個error信息')
42  logyyx.cri('一個致命critical信息')

多模塊使用logging
logging模塊保證在同一個python解釋器內,多次調用logging.getLogger('log_name')都會返回同一個logger實例,即使是在多個模塊的情況下。所以典型的多模塊場景下使用logging的方式是在main模塊中配置logging,這個配置會作用於多個的子模塊,然后在其他模塊中直接通過getLogger獲取Logger對象即可。
配置文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[loggers]
keys=root,main
  
[handlers]
keys=consoleHandler,fileHandler
  
[formatters]
keys=fmt
  
[logger_root]
level=DEBUG
handlers=consoleHandler
  
[logger_main]
level=DEBUG
qualname=main
handlers=fileHandler
  
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=fmt
args=(sys.stdout,)
  
[handler_fileHandler]
class=logging.handlers.RotatingFileHandler
level=DEBUG
formatter=fmt
args=('tst.log','a',20000,5,)
  
[formatter_fmt]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

主模塊main.py:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import logging
import logging.config
  
logging.config.fileConfig( 'logging.conf' )
root_logger = logging.getLogger( 'root' )
root_logger.debug( 'test root logger...' )
  
logger = logging.getLogger( 'main' )
logger.info( 'test main logger' )
logger.info( 'start import module \'mod\'...' )
import mod
  
logger.debug( 'let\'s test mod.testLogger()' )
mod.testLogger()
  
root_logger.info( 'finish test...' )

子模塊mod.py:

?
1
2
3
4
5
6
7
8
9
import logging
import submod
  
logger = logging.getLogger( 'main.mod' )
logger.info( 'logger of mod say something...' )
  
def testLogger():
   logger.debug( 'this is mod.testLogger...' )
   submod.tst()

子子模塊submod.py:

?
1
2
3
4
5
6
7
import logging
  
logger = logging.getLogger( 'main.mod.submod' )
logger.info( 'logger of submod say something...' )
  
def tst():
   logger.info( 'this is submod.tst()...' )

然后運行python main.py,控制台輸出:

?
1
2
3
4
5
6
7
8
9
2012-03-09 18:22:22,793 - root - DEBUG - test root logger...
2012-03-09 18:22:22,793 - main - INFO - test main logger
2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'...
2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something...
2012-03-09 18:22:22,809 - main.mod - INFO - logger say something...
2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger()
2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger...
2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()...
2012-03-09 18:22:22,841 - root - INFO - finish test...

可以看出,和預想的一樣,然后在看一下tst.log,logger配置中的輸出的目的地:

?
1
2
3
4
5
6
7
2012-03-09 18:22:22,793 - main - INFO - test main logger
2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'...
2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something...
2012-03-09 18:22:22,809 - main.mod - INFO - logger say something...
2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger()
2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger...
2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()...

另外在瀏覽網頁時發現一個講的比較好的:http://outofmemory.cn/code-snippet/450/python-rizhi-logging-module-usage-summary

下面這個是目前會用,但是不是甚懂的一個logger系統設計:

 1 import logging
 2 import logging.config
 3 
 4 class SpiderFilter(logging.Filter):
 5 
 6     def __init__(self, allow=None, disable=None):
 7         self.allow_channels = allow
 8         self.disable_channels = disable
 9 
10     def filter(self, record):
11         if self.allow_channels is not None:
12             if record.name in self.allow_channels:
13                 allow = True
14             else:
15                 allow = False
16         elif self.disable_channels is not None:
17             if record.name in self.disable_channels:
18                 allow = False
19             else:
20                 allow = True
21         else:
22             allow = False
23         return allow
24 
25 
26 LOGGING = {
27     'version': 1,
28     'disable_existing_loggers': True,
29     'formatters': {
30         'verbose': {
31             'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
32         },
33         'simple': {
34             'format': '%(asctime)s -- %(name)s !!!%(levelname)s!!!: %(message)s'
35         },
36     },
37     'filters': {
38         'basic': {
39             '()': SpiderFilter,
40             'allow': ('mongo', 'redis', 'mysql'),
41         },
42         'warn': {
43             '()': SpiderFilter,
44             'disable': ()
45         }
46     },
47     'handlers': {
48         'file': {
49             'level': 'WARN',
50             'formatter': 'simple',
51             'class': 'logging.FileHandler',
52             'filename': 'spider.log',
53             'mode': 'a',
54             'filters': ['warn']
55         },
56         'console': {
57             'level': 'DEBUG',
58             'class': 'logging.StreamHandler',
59             'formatter': 'simple'
60         },
61         'database': {
62             'level': 'DEBUG',
63             'class': 'logging.FileHandler',
64             'formatter': 'simple',
65             'filename': 'spider.log',
66             'mode': 'a',
67             'filters': ['basic']
68         }
69     },
70     'loggers': {
71         'mongo': {
72             'handlers':['file'],
73             'propagate': True,
74             'level':'ERROR',
75         },
76         'mysql': {
77             'handlers': ['database'],
78             'level': 'DEBUG',
79             'propagate': False,
80         },
81         'redis': {
82             'handlers': ['console', 'database'],
83             'level': 'INFO',
84             'filters': ['basic']
85         }
86     },
87     'root': {
88         'level': 'DEBUG',
89         'handlers': ['console']
90     }
91 }
92 
93 if __name__ == '__main__':
94     logging.config.dictConfig(LOGGING)
95     logging.getLogger('mysql').debug('Simple Log Test!')
96     logging.getLogger('mongo').critical('Test!')

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM