さまざまなロックを使用するマルチスレッドPythonアプリケーションをデバッグしようとしています。
ロックが取得および解放される場所とタイミングを追跡するためにショット全体にlog.debug(...)ステートメントを配置するのではなく、私の考えは、メソッドthreading.Lock.acquire()およびthreading.Lock.release( )を装飾することです。 、および呼び出しの前に次のようなものを付けます。
log.debug("lock::acquire() [%s.%s.%s]" %
(currentThread().getName(),
self.__class__.__name__,
sys._getframe().f_code.co_name))
ここで、logはグローバルロギングオブジェクトです-議論のために。
理想的には、ログエントリの「lock」という名前は実行時に派生する必要があります。これにより、ログでこれらのメソッドが呼び出されるロックオブジェクトに関係なく、名前、装飾された操作、現在のスレッド、クラス、および関数が出力されます。操作(取得|解放)が呼び出されます。
免責事項:上記のコードは、このようなデコレータの実装には不十分であることを認めます。これは、私が達成できると思うことの味を与えるためだけに提供されています。
スレッドライブラリの元のソースコードをドクターせずに、つまり呼び出し元のアプリケーションコード内から、標準ライブラリメソッドを装飾できるかどうか誰かが知っていますか?
おそらく私は間違った木を吠えていますが、デコレータを使用せずに同じ目的を達成するためのより良い方法がありますか?これが実際に当てはまる場合は、ガイダンスを事前に感謝します。
解決策:(lazyrに触発されて)
次のコードは、ロック操作をログに記録し、ロック操作を呼び出すメソッド/関数の名前を示します(Conditionsとその追加のwait()およびnotify()メソッドで動作するようにコードを調整しています)。
# Class to wrap Lock and simplify logging of lock usage
class LogLock(object):
"""
Wraps a standard Lock, so that attempts to use the
lock according to its API are logged for debugging purposes
"""
def __init__(self, name, log):
self.name = str(name)
self.log = log
self.lock = threading.Lock()
self.log.debug("{0} created {1}".format(
inspect.stack()[1][3], self.name))
def acquire(self, blocking=True):
self.log.debug("{0} trying to acquire {1}".format(
inspect.stack()[1][3], self.name))
ret = self.lock.acquire(blocking)
if ret == True:
self.log.debug("{0} acquired {1}".format(
inspect.stack()[1][3], self.name))
else:
self.log.debug("{0} non-blocking acquire of {1} lock failed".format(
inspect.stack()[1][3], self.name))
return ret
def release(self):
self.log.debug("{0} releasing {1}".format(inspect.stack()[1][3], self.name))
self.lock.release()
def __enter__(self):
self.acquire()
def __exit__(self, exc_type, exc_val, exc_tb):
self.release()
return False # Do not swallow exceptions
ログインスタンスがLogLockに渡された場所。initはlogging.Formatterで次のように定義され、呼び出し元のスレッドのIDを取得しました。
# With the following format
log_format = \
logging.Formatter('%(asctime)s %(levelname)s %(threadName)s %(message)s')