包括我在內的大多數人,當編寫小型腳本時,習慣使用print來debug,肥腸方便,這沒問題,但隨著代碼不斷完善,日志功能一定是不可或缺的,極大程度方便問題溯源以及甩鍋,也是每個工程師必備技能。
Python自帶的logging我個人不推介使用,不太Pythonic,而開源的Loguru庫成為眾多工程師及項目中首選,本期將同時對logging及Loguru進行使用對比,希望有所幫助。
在logging中,默認的日志功能輸出的信息較為有限:
import logginglogger = logging.getLogger(__name__)def main(): logger.debug("This is a debug message") logger.info("This is an info message") logger.warning("This is a warning message") logger.error("This is an error message")if __name__ == "__main__": main()
輸出(logging默認日志等級為warning,故此處未輸出info與debug等級的信息):
WARNING:root:This is a warning messageERROR:root:This is an error message
再來看看loguru,默認生成的信息就較為豐富了:
from loguru import loggerdef main(): logger.debug("This is a debug message") logger.info("This is an info message") logger.warning("This is a warning message") logger.error("This is an error message")if __name__ == "__main__": main()
提供了執行時間、等級、在哪個函數調用、具體哪一行等信息。
格式化日志允許我們向日志添加有用的信息,例如時間戳、日志級別、模塊名稱、函數名稱和行號。
在logging中使用%達到格式化目的:
import logging# Create a logger and set the logging levellogging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)s | %(module)s:%(funcName)s:%(lineno)d - %(message)s", datefmt="%Y-%m-%d %H:%M:%S",)logger = logging.getLogger(__name__)def main(): logger.debug("This is a debug message") logger.info("This is an info message") logger.warning("This is a warning message") logger.error("This is an error message")
輸出:
2023-10-18 15:47:30 | INFO | tmp:<module>:186 - This is an info message2023-10-18 15:47:30 | WARNING | tmp:<module>:187 - This is a warning message2023-10-18 15:47:30 | ERROR | tmp:<module>:188 - This is an error message
而loguru使用和f-string相同的{}格式,更方便:
from loguru import loggerlogger.add( sys.stdout, level="INFO", format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {module}:{function}:{line} - {message}",)
在logging中,實現日志保存與日志打印需要兩個額外的類,FileHandler 和 StreamHandler:
import logginglogging.basicConfig( level=logging.DEBUG, format="%(asctime)s | %(levelname)s | %(module)s:%(funcName)s:%(lineno)d - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", handlers=[ logging.FileHandler(filename="/your/save/path/info.log", level=logging.INFO), logging.StreamHandler(level=logging.DEBUG), ],)logger = logging.getLogger(__name__)def main(): logging.debug("This is a debug message") logging.info("This is an info message") logging.warning("This is a warning message") logging.error("This is an error message")if __name__ == "__main__": main()
但是在loguru中,只需要使用add方法即可達到目的:
from loguru import loggerlogger.add( 'info.log', format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {module}:{function}:{line} - {message}", level="INFO",)def main(): logger.debug("This is a debug message") logger.info("This is an info message") logger.warning("This is a warning message") logger.error("This is an error message")if __name__ == "__main__": main()
日志輪換指通過定期創建新的日志文件并歸檔或刪除舊的日志來防止日志變得過大。
在logging中,需要一個名為 TimedRotatingFileHandler 的附加類,以下代碼示例代表每周切換到一個新的日志文件 ( when=“WO”, interval=1 ),并保留最多 4 周的日志文件 ( backupCount=4 ):
import loggingfrom logging.handlers import TimedRotatingFileHandlerlogger = logging.getLogger(__name__)logger.setLevel(logging.DEBUG)# Create a formatter with the desired log formatformatter = logging.Formatter( "%(asctime)s | %(levelname)-8s | %(module)s:%(funcName)s:%(lineno)d - %(message)s", datefmt="%Y-%m-%d %H:%M:%S",)file_handler = TimedRotatingFileHandler( filename="debug2.log", when="WO", interval=1, backupCount=4)file_handler.setLevel(logging.INFO)file_handler.setFormatter(formatter)logger.addHandler(file_handler)def main(): logger.debug("This is a debug message") logger.info("This is an info message") logger.warning("This is a warning message") logger.error("This is an error message")if __name__ == "__main__": main()
在loguru中,可以通過將 rotation 和 retention 參數添加到 add 方法來達到目的,如下示例,同樣肥腸方便:
from loguru import loggerlogger.add("debug.log", level="INFO", rotation="1 week", retention="4 weeks")def main(): logger.debug("This is a debug message") logger.info("This is an info message") logger.warning("This is a warning message") logger.error("This is an error message")if __name__ == "__main__": main()
日志篩選指根據特定條件有選擇的控制應輸出與保存哪些日志信息。
在logging中,實現該功能需要創建自定義日志過濾器類:
import logginglogging.basicConfig( filename="test.log", format="%(asctime)s | %(levelname)-8s | %(module)s:%(funcName)s:%(lineno)d - %(message)s", level=logging.INFO,)class CustomFilter(logging.Filter): def filter(self, record): return "Cai Xukong" in record.msg# Create a custom logging filtercustom_filter = CustomFilter()# Get the root logger and add the custom filter to itlogger = logging.getLogger()logger.addFilter(custom_filter)def main(): logger.info("Hello Cai Xukong") logger.info("Bye Cai Xukong")if __name__ == "__main__": main()
在loguru中,可以簡單地使用lambda函數來過濾日志:
from loguru import loggerlogger.add("test.log", filter=lambda x: "Cai Xukong" in x["message"], level="INFO")def main(): logger.info("Hello Cai Xukong") logger.info("Bye Cai Xukong")if __name__ == "__main__": main()
在logging中捕獲異常較為不便且難以調試,如:
import logginglogging.basicConfig( level=logging.DEBUG, format="%(asctime)s | %(levelname)s | %(module)s:%(funcName)s:%(lineno)d - %(message)s", datefmt="%Y-%m-%d %H:%M:%S",)def division(a, b): return a / bdef nested(c): try: division(1, c) except ZeroDivisionError: logging.exception("ZeroDivisionError")if __name__ == "__main__": nested(0)
Traceback (most recent call last): File "logging_example.py", line 16, in nested division(1, c) File "logging_example.py", line 11, in division return a / bZeroDivisionError: division by zero
上面輸出的信息未提供觸發異常的c值信息,而在loguru中,通過顯示包含變量值的完整堆棧跟蹤來方便用戶識別:
Traceback (most recent call last): File "logging_example.py", line 16, in nested division(1, c) File "logging_example.py", line 11, in division return a / bZeroDivisionError: division by zero
值得一提的是,loguru中的catch裝飾器允許用戶捕獲函數內任何錯誤,且還會標識發生錯誤的線程:
from loguru import loggerdef division(a, b): return a / b@logger.catchdef nested(c): division(1, c)if __name__ == "__main__": nested(0)
OK,作為普通玩家以上功能足以滿足日常日志需求,通過對比logging與loguru應該讓大家有了直觀感受,哦對了,loguru如何安裝?
pip install loguru
以上就是本期的全部內容,期待點贊在看,我是啥都生,下次再見。
本文鏈接:http://www.www897cc.com/showinfo-26-17257-0.html為什么不推薦使用Python原生日志庫?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 如何將Docker的構建時間減少40%
下一篇: Gorm 中的遷移指南