メッセージを表示するためにPythonのロギングモジュールを使用するプロジェクトに取り組んでいます。共通のリポジトリからのモジュールを使用する独自のプロジェクトがあるので、コードのその部分のロギングステートメントを変更したくありません。
ただし、メモリ使用量は私のプログラムではかなり問題になっているようです。そのため、次のように、時間とメッセージとともに、各ログステートメントにメモリ使用量を記録したいと思います。
YYYY-MM-DD HH:MM:SS,mmm NAME LEVEL MemTotal:#M,Swap:#M MESSAGE
ロギングモジュールを使用してこれを行う簡単な方法はありますか?
フィルタを使用してコンテキスト情報を追加する方法だと思います(http://docs.python.org/howto/logging-cookbook.html#filters-contextualを参照)。)が、このフィルターをすべてのレベルとロガーのすべてのインスタンスに一度に追加する方法はないようです。ドキュメントでは、外部モジュールでフィルターを使用しないため、ロガーではなくハンドラーにフィルターを追加することを提案しています。ただし、これを最も明白な方法(ハンドラーを作成し、フィルターを追加してから、ハンドラーをルートロガーにアタッチする)で行うと、予期しない動作が発生しました。出力がまったくなく、エラーメッセージも表示されないか、(basicConfigを最初に使用した場合)エラーメッセージが表示されることを除いて、正しい動作が得られました。最後のケースでは、実際には2つのハンドラーがあり、1つは正しく機能し、もう1つは誤って動作していると思います。
これまでのところ、私は次の解決策を考え出しましたが、これはあまりエレガントではないと思います(https://stackoverflow.com/a/938800/819110に感謝します)。醜い部分は、ロガーからハンドラーを手動で抽出し、それにフィルターを追加する必要があることです。設定ファイルにフィルタを追加できないようです。これははるかに便利です。それでも、このアプローチは(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質問を参照しました。