我使用python的日誌記錄模塊來顯示消息。我有我自己的項目,它使用來自公共存儲庫的模塊,所以我不想更改該部分代碼中的任何日誌語句。使用Python日誌記錄內存使用情況統計信息
但是,內存使用情況似乎是相當一個問題在我的計劃,所以我想登錄內存使用情況在每個日誌陳述,旁邊的時間和消息,就像這樣:
YYYY-MM-DD HH:MM:SS,mmm NAME LEVEL MemTotal:#M,Swap:#M MESSAGE
是有一個簡單的方法來使用日誌記錄模塊來做到這一點?
我想通過使用Filter來添加上下文信息(參見http://docs.python.org/howto/logging-cookbook.html#filters-contextual),但似乎沒有辦法將此Filter同時添加到所有級別和所有記錄器實例。 該文檔建議將過濾器添加到處理程序而不是記錄器,因爲否則它將不使用外部模塊中的過濾器。以最明顯的方式執行此操作(創建Handler,添加Filter,然後將Handler附加到根Logger)卻給我帶來了意想不到的行爲。我根本沒有輸出,也沒有錯誤消息,或者(當首先使用basicConfig時)我得到了正確的行爲,除了它也給出了錯誤消息。我懷疑在最後一個案例中,我確實得到了兩個處理者,其中一個處理正確,另一個錯誤地處理。
到目前爲止,我已經想出了以下解決方案,我不認爲這是相當高雅的 (感謝https://stackoverflow.com/a/938800/819110)。醜陋的部分是我必須手工從記錄器中提取Handler,並將Filter添加到它。我似乎無法添加一個過濾器到配置文件,這會更方便。儘管如此,這種方法似乎可行(在Linux上),儘管我懷疑應該有一種更直接的方法來做到這一點。
import logging
import external_module
class MemuseFilter(logging.Filter):
def filter(self, record):
""" This function overrides logging.Filter, adds memuse as a field
"""
record.memuse = self.str_mem()
return True
# Following code from https://stackoverflow.com/a/938800/819110:
_proc_status = '/proc/%d/status' % os.getpid()
_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
'KB': 1024.0, 'MB': 1024.0*1024.0}
def _VmB(self,VmKey):
"""Private.
"""
# get pseudo file /proc/<pid>/status
try:
t = open(self._proc_status)
v = t.read()
t.close()
except:
return 0.0 # non-Linux?
# get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
i = v.index(VmKey)
v = v[i:].split(None, 3) # whitespace
if len(v) < 3:
return 0.0 # invalid format?
# convert Vm value to bytes
return float(v[1]) * self._scale[v[2]]
def memory(self,since=0.0):
"""Return memory usage in bytes.
"""
return self._VmB('VmSize:') - since
def swapsize(self,since=0.0):
"""Return swap size in bytes.
"""
return self._VmB('VmSwap:') - since
def byte_to_mb(self,byte):
"""return size in MB (being lazy)
"""
return byte/(1024*1024)
def str_mem(self):
"""Return a string with the total memuse and swap size in MB
"""
return "MemTotal:%.0fM,Swap:%.0fM"%(\
self.byte_to_mb(self.memory()),self.byte_to_mb(self.swapsize()))
if __name__ == '_main__':
logging.config.fileConfig('logging.conf') # Get basic config
log = logging.getLogger('') # Get root logger
f = MemuseFilter() # Create filter
log.handlers[0].addFilter(f) # The ugly part:adding filter to handler
log.warning("Foo")
function_from_module_using_logging()
凡external_module
讀這樣的事情:
log = logging.getLogger(__name__)
def function_from_module_using_logging():
log.warning("Bar")
和logging.conf
是這樣的:
[loggers]
keys=root
[handlers]
keys=fileHandler
[formatters]
keys=memuseFormatter
[logger_root]
level=DEBUG
handlers=fileHandler
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=memuseFormatter
args=('some.log','w')
[formatter_memuseFormatter]
format=%(asctime)-15s %(name)-5s %(levelname)-8s %(memuse)-22s %(message)s
datefmt=
更好的解決方案將是最歡迎!
編輯:引用了錯誤的SO問題。
爲什麼'_scale'字典中'1024.0'而不是'1024'?看起來整數比浮點更適合。 – Matt
我承認我很懶,爲此只需複製http://stackoverflow.com/a/938800/819110。我想你是對的。 雖然(用於這個)只需要從Vm中獲取的字符串並且無需轉換即可通過(僅刪除換行符),這已經足夠了 – mmvdv