Loguru是一個旨在在Python中帶來愉快伐木的圖書館。
您是否曾經對配置記錄儀和二手print()
感到懶惰?...我做到了,但是記錄對於每個應用程序都是基礎的,並簡化了調試過程。使用Loguru,您沒有任何藉口從一開始就不使用日誌記錄,這與from loguru import logger
一樣簡單。
此外,該庫旨在通過添加一堆有用的功能來解決標準記錄器的警告,從而使Python記錄減少痛苦。 Loguru試圖使其既令人愉悅又強大。
pip install loguru
Loguru的主要概念是只有一個也是一個logger
。
為了方便起見,它是預先配置的,並從stderr
輸出以開始(但這是完全可配置的)。
from loguru import logger
logger . debug ( "That's it, beautiful and simple logging!" )
logger
只是一個接口,將日誌消息分配給配置的處理程序。簡單,對嗎?
如何添加處理程序?如何設置日誌格式化?如何過濾消息?如何設置水平?
一個答案: add()
函數。
logger . add ( sys . stderr , format = "{time} {level} {message}" , filter = "my_module" , level = "INFO" )
該功能應用於註冊負責使用記錄dict上下文的日誌消息的匯。接收器可以採用多種形式:簡單功能,字符串路徑,類似文件的對象,coroutine功能或內置處理程序。
請注意,您還可以在添加時使用返回的標識符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 )
還支持用作水槽的Coroutine功能,並應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-什麼?!
Trackback(最近的最新電話):
文件“ test.py”,第12行,<module>
嵌套(0)
└<<函數嵌套在0x7f5c7553222f0>
>文件“ test.py”,第8行,嵌套
功能(5,c)
│└0
└<<函數func在0x7f5c79fc2e18>
文件“ test.py”,第4行,在func中
返回A / B
│└0
└5
ZerodivisionError:零部門
請注意,由於不可用的幀數據,此功能在默認的Python depl上無法使用。
另請參閱:使用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()
方法允許將動態值附加到每個新消息的記錄下:
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
and %(created)s
,沒有時區信息的Naive DateTimes,而不是直觀的格式等。
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 sinks?
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可以輕鬆地與出色的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中以最大的速度實現。