Loguruは、Pythonに楽しいロギングをもたらすことを目的としたライブラリです。
代わりにロガーと使用したprint()
構成について怠zyと感じたことはありますか?... Loguruを使用すると、最初からロギングを使用しないという言い訳がありません。これはfrom loguru import logger
同じくらい簡単です。
また、このライブラリは、標準ロガーの警告を解決する有用な機能をたくさん追加することにより、Pythonの伐採をより痛みを軽減することを目的としています。アプリケーションでログを使用することは自動化である必要があり、 Loguruはそれを心地よく強力にしようとします。
pip install loguru
Loguruの主な概念は、1つのlogger
が1つしかないことです。
便利なため、それは事前に構成され、最初からstderr
に出力されます(ただし、それは完全に構成可能です)。
from loguru import logger
logger . debug ( "That's it, beautiful and simple logging!" )
logger
構成されたハンドラーにログメッセージをディスパッチする単なるインターフェイスです。シンプルですよね?
ハンドラーを追加する方法は?ログのフォーマットを設定する方法は?メッセージをフィルタリングする方法は?レベルを設定する方法は?
1つの答え: add()
関数。
logger . add ( sys . stderr , format = "{time} {level} {message}" , filter = "my_module" , level = "INFO" )
この関数は、レコードDICTでコンテキスト化されたログメッセージの管理を担当するシンクを登録するために使用する必要があります。シンクは、単純な関数、文字列パス、ファイルのようなオブジェクト、コルーチン関数、または組み込みハンドラーなど、さまざまな形をとることができます。
また、追加された識別子を使用して、以前に追加されたハンドラーをremove()
こともできます。これは、デフォルトのstderr
ハンドラーに取って代わる場合に特に便利です: logger.remove()
を呼び出して、新たなスタートを立てるだけです。
ログに記録されたメッセージをファイルに送信する場合は、シンクとして文字列パスを使用するだけです。利便性のために自動的にタイミングを合わせることもできます。
logger . add ( "file_{time}.log" )
また、ロガーを回転する必要がある場合、古いログを削除する場合、または閉鎖時にファイルを圧縮する場合にも簡単に構成できます。
logger . add ( "file_1.log" , rotation = "500 MB" ) # Automatically rotate too big file
logger . add ( "file_2.log" , rotation = "12:00" ) # New file is created each day at noon
logger . add ( "file_3.log" , rotation = "1 week" ) # Once the file is too old, it's rotated
logger . add ( "file_X.log" , retention = "10 days" ) # Cleanup after some time
logger . add ( "file_Y.log" , compression = "zip" ) # Save some loved space
Loguruは、はるかにエレガントで強力な{}
フォーマットを%
超えて、ロギング関数は実際にはstr.format()
に相当します。
logger . info ( "If you're using Python {}, prefer {feature} of course!" , 3.6 , feature = "f-strings" )
ログファイルに何も見ずにプログラムが予期せずクラッシュするのを見たことがありますか?スレッドで発生する例外が記録されていないことに気づいたことがありますか?これは、 catch()
デコレーター /コンテキストマネージャーを使用して解決できます。これにより、エラーがlogger
に正しく伝播されるようにします。
@ logger . catch
def my_function ( x , y , z ):
# An error? It's caught anyway!
return 1 / ( x + y + z )
Loguruは、端末が互換性がある場合、ログに色を自動的に追加します。シンク形式でマークアップタグを使用して、お気に入りのスタイルを定義できます。
logger . add ( sys . stdout , colorize = True , format = "<green>{time}</green> <level>{message}</level>" )
logger
に追加されたすべてのシンクは、デフォルトでスレッドセーフです。それらはマルチプロセスセーフではありませんが、ログの整合性を確保するためにメッセージenqueue
ことができます。この同じ引数は、非同期ロギングが必要な場合にも使用できます。
logger . add ( "somefile.log" , enqueue = True )
シンクとして使用されるコルーチン関数もサポートされており、 complete()
で待機する必要があります。
コードで発生する例外を記録することは、バグを追跡するために重要ですが、なぜ失敗したのかわからない場合は非常に役に立ちません。 Loguruは、変数の値を含むスタックトレース全体を表示できるようにすることで、問題を特定するのに役立ちます(これにはbetter_exceptions
感謝します!)。
コード:
# Caution, "diagnose=True" is the default and may leak sensitive data in prod
logger . add ( "out.log" , backtrace = True , diagnose = True )
def func ( a , b ):
return a / b
def nested ( c ):
try :
func ( 5 , c )
except ZeroDivisionError :
logger . exception ( "What?!" )
nested ( 0 )
結果:
2018-07-17 01:38:43.975 |エラー| __main __:ネスト:10-何?!
Traceback(最新のコールLast):
ファイル「test.py」、12行目、<module>
ネスト(0)
└<0x7F5C755322F0>にネストされています
> file "test.py"、nestedの8行
func(5、c)
│0
└<0x7F5C79FC2E18>の関数FUNC
FUNCの「test.py」、4行目
a / bを返します
│0
└5
ZerodivisionError:ゼロによる分割
この機能は、利用できないフレームデータのため、デフォルトのPython REPLで動作しないことに注意してください。
参照:Loguruを使用する場合のセキュリティ上の考慮事項。
解析を簡単にするために、ログをシリアル化したいですか、またはそれらを渡すようにしたいですか? serialize
引数を使用して、各ログメッセージはJSON文字列に変換され、構成されたシンクに送信されます。
logger . add ( custom_sink_function , serialize = True )
bind()
使用すると、追加のレコード属性を変更することにより、ロガーメッセージをコンテキスト化できます。
logger . add ( "file.log" , format = "{extra[ip]} {extra[user]} {message}" )
context_logger = logger . bind ( ip = "192.168.0.1" , user = "someone" )
context_logger . info ( "Contextualize your logger easily" )
context_logger . bind ( user = "someone_else" ). info ( "Inline binding of extra attribute" )
context_logger . info ( "Use kwargs to add context during formatting: {user}" , user = "anybody" )
contextualize()
で一時的にコンテキストローカル状態を変更することが可能です。
with logger . contextualize ( task = task_id ):
do_something ()
logger . info ( "End of task" )
また、 bind()
とfilter
を組み合わせることにより、ログに対してより細粒の制御を行うこともできます。
logger . add ( "special.log" , filter = lambda record : "special" in record [ "extra" ])
logger . debug ( "This message is not logged to the file" )
logger . bind ( special = True ). info ( "This message, though, is logged to the file!" )
最後に、 patch()
メソッドにより、新しいメッセージの各レコードDICTに動的値を添付することができます。
logger . add ( sys . stderr , format = "{extra[utc]} {message}" )
logger = logger . patch ( lambda record : record [ "extra" ]. update ( utc = datetime . utcnow ()))
生産中のパフォーマンスペナルティなしで冗長情報を記録したい場合は、 opt()
メソッドを使用してこれを達成できます。
logger . opt ( lazy = True ). debug ( "If sink level <= DEBUG: {x}" , x = lambda : expensive_function ( 2 ** 64 ))
# By the way, "opt()" serves many usages
logger . opt ( exception = True ). info ( "Error stacktrace added to the log message (tuple accepted too)" )
logger . opt ( colors = True ). info ( "Per message <blue>colors</blue>" )
logger . opt ( record = True ). info ( "Display values from the record (eg. {record[thread]})" )
logger . opt ( raw = True ). info ( "Bypass sink formatting n " )
logger . opt ( depth = 1 ). info ( "Use parent stack context (useful within wrapped functions)" )
logger . opt ( capture = False ). info ( "Keyword arguments not added to {dest} dict" , dest = "extra" )
Loguruには、 trace()
とsuccess()
が追加されるすべての標準ロギングレベルが付属しています。もっと必要ですか?次に、 level()
関数を使用して作成するだけです。
new_level = logger . level ( "SNAKY" , no = 38 , color = "<yellow>" , icon = "?" )
logger . log ( "SNAKY" , "Here we go!" )
標準ロギングは、 datefmt
やmsecs
、 %(asctime)s
および%(created)s
、timezone情報のないナイーブデータのような引数で肥大化しています。直感的なフォーマットではありません。
logger . add ( "file.log" , format = "{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}" )
スクリプトでロガーを使用するのは簡単で、開始時にconfigure()
できます。ライブラリ内からloguruを使用するには、 add()
を呼び出さdisable()
ようにしてください。開発者がライブラリのログを表示したい場合は、再度enable()
ことができます。
# For scripts
config = {
"handlers" : [
{ "sink" : sys . stdout , "format" : "{time} - {message}" },
{ "sink" : "file.log" , "serialize" : True },
],
"extra" : { "user" : "someone" }
}
logger . configure ( ** config )
# For libraries, should be your library's `__name__`
logger . disable ( "my_library" )
logger . info ( "No matter added sinks, this message is not displayed" )
# In your application, enable the logger in the library
logger . enable ( "my_library" )
logger . info ( "This message however is propagated to the sinks" )
追加の利便性のために、 loguru-config
ライブラリを使用して、構成ファイルからlogger
直接セットアップすることもできます。
組み込みのロギングHandler
をLoguruシンクとして使用したいですか?
handler = logging . handlers . SysLogHandler ( address = ( 'localhost' , 514 ))
logger . add ( handler )
Loguruメッセージを標準のロギングに伝播する必要がありますか?
class PropagateHandler ( logging . Handler ):
def emit ( self , record : logging . LogRecord ) -> None :
logging . getLogger ( record . name ). handle ( record )
logger . add ( PropagateHandler (), format = "{message}" )
Loguruシンクに向けて標準ロギングメッセージを傍受したいですか?
class InterceptHandler ( logging . Handler ):
def emit ( self , record : logging . LogRecord ) -> None :
# Get corresponding Loguru level if it exists.
level : str | int
try :
level = logger . level ( record . levelname ). name
except ValueError :
level = record . levelno
# Find caller from where originated the logged message.
frame , depth = inspect . currentframe (), 0
while frame and ( depth == 0 or frame . f_code . co_filename == logging . __file__ ):
frame = frame . f_back
depth += 1
logger . opt ( depth = depth , exception = record . exc_info ). log ( level , record . getMessage ())
logging . basicConfig ( handlers = [ InterceptHandler ()], level = 0 , force = True )
デフォルトのロガーのフォーマットが気に入らない?別のDEBUG
色を好むでしょうか?問題ない:
# Linux / OSX
export LOGURU_FORMAT = "{time} | <lvl>{message}</lvl>"
# Windows
setx LOGURU_DEBUG_COLOR "<green>"
生成されたログから特定の情報を抽出することがしばしば役立つことがよくあります。これが、Loguruがログと正規表現に対処するのに役立つparse()
メソッドを提供する理由です。
pattern = r"(?P<time>.*) - (?P<level>[0-9]+) - (?P<message>.*)" # Regex with named groups
caster_dict = dict ( time = dateutil . parser . parse , level = int ) # Transform matching groups
for groups in logger . parse ( "file.log" , pattern , cast = caster_dict ):
print ( "Parsed:" , groups )
# {"level": 30, "message": "Log example", "time": datetime(2018, 12, 09, 11, 23, 55)}
Loguruは、Great notifiers
ライブラリと簡単に組み合わせて(個別にインストールする必要があります)、プログラムが予期せずに失敗したときに電子メールを受信したり、他の多くの種類の通知を送信したりできます。
import notifiers
params = {
"username" : "[email protected]" ,
"password" : "abc123" ,
"to" : "[email protected]"
}
# Send a single notification
notifier = notifiers . get_notifier ( "gmail" )
notifier . notify ( message = "The application is running!" , ** params )
# Be alerted on each error message
from notifiers . logging import NotificationHandler
handler = NotificationHandler ( "gmail" , defaults = params )
logger . add ( handler , level = "ERROR" )
ほとんどの場合、パフォーマンスへの伐採の影響は無視できますが、ゼロコストのロガーは、あまり懸念なくどこでもそれを使用することができます。今後のリリースでは、Loguruの重要な関数がCで最大速度で実装されます。