python中的log日志多線程安全
python log日志多線程安全
python中的日志文件為logger,常用的有兩個-RotatingFileHandler;TimedRotatingFileHandler。
文件沒滿足分割條件前,保存在‘info.log’(自己命名的文件)中,如果滿足分割條件,會生成‘info.log.1’。
下一次滿足分割條件后,將‘info.log’保存成‘info.log.1’,而‘info.log.1’順延成‘info.log.2’;滿足最多保存的個數(shù)后,會將其刪掉。
RotatingFileHandler,是按大小劃分日志文件,使用方法如下。
RotatingFileHandler是按文件大小自動分割保存,下文中設(shè)置的是1M保存一個文件,最多保存30個。
此種方式支持多線程安全,支持軟件的開關(guān)機(TimedRotatingFileHandler不支持,一旦關(guān)機,會重新計時)
import logging from logging import handlers def log_init(): ? ? log = logging.getLogger('error.log') ? ? ? ? ? ?# log保存位置 ? ? format_str = log.Formatter('%(asctime)s - \ ? ? # log時間戳格式 ? ? ? ? %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s') ? ? ? ? ? ? ? ? ? ? ? ?? ? ? log.setLevel(logging.DEBUG) ? ? ? ? ? ? ? ? ? ? # log日志等級(往下的內(nèi)容不保存) ? ? sh = logging.StreamHandler() ? ? ? ? ? ? ? ? ? ?# 往屏幕上輸出 ? ? # filename:log文件名;maxBytes:超過最大尺寸,log會另存一個文件; ? ? # backupCount:最多保存多少個日志;encoding:保存編碼格式 ? ? th = handlers.RotatingFileHandler(filename='error.log', maxBytes=1024*1024, \ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? backupCount=30, encoding='uft-8') ? ? ? ? ? ? th.setFormatter(format_str) ? ? ? ? ? ? ? ? ? ? # 設(shè)置文件里寫入的格式 ? ? log.addHandler(sh) ? ? log.addHandler(th) ? ? return log if __name__ == '__main__': ? ? log = log_init() ? ? log.debug('debug_msg') ? ? log.info('info_msg') ? ? log.warning('warning_msg') ? ? log.error('error_msg') ? ? log.critical('critical_msg')
TimedRotatingFileHandler是按日期劃分日志文件,使用方法如下。
TimedRotatingFileHandler是按文件大小自動分割保存,下文中設(shè)置的是每天保存一個log文件,最多保存30個。
此種方式支持多線程不安全,不支持軟件的關(guān)機(軟件關(guān)機后,會重新計時,如果經(jīng)常關(guān)機的項目,會只記錄在一個文件中)。
import logging from logging import handlers def log_init(): ? ? log = logging.getLogger('error.log') ? ? ? ? ? ?# log保存位置 ? ? format_str = log.Formatter('%(asctime)s - \ ? ? # log時間戳格式 ? ? ? ? %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s') ? ? ? ? ? ? ? ? ? ? ? ?? ? ? log.setLevel(logging.DEBUG) ? ? ? ? ? ? ? ? ? ? # log日志等級(往下的內(nèi)容不保存) ? ? sh = logging.StreamHandler() ? ? ? ? ? ? ? ? ? ?# 往屏幕上輸出 ? ? # filename:log文件名;when:多久另存一個文件(S/M/H/D/W/midnight); ? ? # backupCount:最多保存多少個日志;encoding:保存編碼格式 ? ? th = handlers.TimedRotatingFileHandler(filename='error.log', when='D', \ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? backupCount=30, encoding='uft-8') ? ? ? ? ? ? th.setFormatter(format_str) ? ? ? ? ? ? ? ? ? ? # 設(shè)置文件里寫入的格式 ? ? log.addHandler(sh) ? ? log.addHandler(th) ? ? return log if __name__ == '__main__': ? ? log = log_init() ? ? log.debug('debug_msg') ? ? log.info('info_msg') ? ? log.warning('warning_msg') ? ? log.error('error_msg') ? ? log.critical('critical_msg')
如果想多線程使用TimedRotatingFileHandler,就需要自己寫一個線程,然后每一個log往消息隊列中丟,用線程處理這個消息隊列。
Queue是線程安全的,所以作為消息隊列使用沒有影響。
import time import _thread import logging from logging import handlers from queue import Queue logs_queue = Queue() class LogMsg(object): ? ? def __init__(self, type, msg): ? ? ? ? self._type = type ? ? ? ? self._msg = msg def log_init(): ? ? log = logging.getLogger('error.log') ? ? ? ? ? ?# log保存位置 ? ? format_str = log.Formatter('%(asctime)s - \ ? ? # log時間戳格式 ? ? ? ? %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s') ? ? ? ? ? ? ? ? ? ? ? ?? ? ? log.setLevel(logging.DEBUG) ? ? ? ? ? ? ? ? ? ? # log日志等級(往下的內(nèi)容不保存) ? ? sh = logging.StreamHandler() ? ? ? ? ? ? ? ? ? ?# 往屏幕上輸出 ? ? # filename:log文件名;when:多久另存一個文件(S/M/H/D/W/midnight); ? ? # backupCount:最多保存多少個日志;encoding:保存編碼格式 ? ? th = handlers.TimedRotatingFileHandler(filename='error.log', when='D', \ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? backupCount=30, encoding='uft-8') ? ? ? ? ? ? th.setFormatter(format_str) ? ? ? ? ? ? ? ? ? ? # 設(shè)置文件里寫入的格式 ? ? log.addHandler(sh) ? ? log.addHandler(th) ? ? return log def cop_log_queue(logger): ? ? while True: ? ? ? ? if logs_queue.empty(): ? ? ? ? ? ?time.sleep(1) ? ? ? ? log_msg = logs_queue.get() ? ? ? ? if log_msg._type == 'debug': ? ? ? ? ? ? logger.debug(log_msg._msg) ? ? ? ? elif log_msg._type == 'info': ? ? ? ? ? ? logger.info(log_msg._msg) ? ? ? ? elif log_msg._type == 'warning': ? ? ? ? ? ? logger.warning(log_msg._msg) ? ? ? ? elif log_msg._type == 'error': ? ? ? ? ? ? logger.error(log_msg._msg) ? ? ? ? elif log_msg._type == 'critical': ? ? ? ? ? ? logger.critical(log_msg._msg) def error_thread1(): ? ? while True: ? ? ? ? logs_queue.put(LogMsg('debug','debug_msg')) ? ? ? ? time.sleep(1) def error_thread2(): ? ? while True: ? ? ? ? logs_queue.put(LogMsg('info','info_msg')) ? ? ? ? time.sleep(1) if __name__ == '__main__': ? ? logger = log_init() ? ? _thread.start_new_thread(cope_log_queue, (logger, )) ? ? _thread.start_new_thread(error_thread1, ()) ? ? _thread.start_new_thread(error_thread2, ())
python之log日志
記錄程序日志信息的目的是
- 可以很方便的了解程序的運行情況
- 可以分析用戶的操作行為、喜好等信息
- 方便開發(fā)人員檢查bug
logging日志級別介紹
日志等級可以分為5個,從低到高分別是:
- DEBUG
- INFO
- WARNING
- ERROR
- CRITICAL
日志等級說明:
- DEBUG:程序調(diào)試bug時使用
- INFO:程序正常運行時使用
- WARNING:程序未按預(yù)期運行時使用,但并不是錯誤,如:用戶登錄密碼錯誤
- ERROR:程序出錯誤時使用,如:IO操作失敗
- CRITICAL:特別嚴重的問題,導(dǎo)致程序不能再繼續(xù)運行時使用,如:磁盤空間為空,一般很少使用
- 默認的是WARNING等級,當(dāng)在WARNING或WARNING之上等級的才記錄日志信息。
- 日志等級從低到高的順序是: DEBUG < INFO < WARNING < ERROR < CRITICAL
logging日志的使用
在 logging 包中記錄日志的方式有兩種:
- 輸出到控制臺
- 保存到日志文件
日志信息輸出到控制臺的示例代碼:
import logging logging.debug('這是一個debug級別的日志信息') logging.info('這是一個info級別的日志信息') logging.warning('這是一個warning級別的日志信息') logging.error('這是一個error級別的日志信息') logging.critical('這是一個critical級別的日志信息')
運行結(jié)果:
WARNING:root:這是一個warning級別的日志信息
ERROR:root:這是一個error級別的日志信息
CRITICAL:root:這是一個critical級別的日志信息
說明:
日志信息只顯示了大于等于WARNING級別的日志,這說明默認的日志級別設(shè)置為WARNING
logging日志等級和輸出格式的設(shè)置:
import logging # 設(shè)置日志等級和輸出日志格式 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') logging.debug('這是一個debug級別的日志信息') logging.info('這是一個info級別的日志信息') logging.warning('這是一個warning級別的日志信息') logging.error('這是一個error級別的日志信息') logging.critical('這是一個critical級別的日志信息')
運行結(jié)果:
2019-02-13 20:41:33,080 - hello.py[line:6] - DEBUG: 這是一個debug級別的日志信息
2019-02-13 20:41:33,080 - hello.py[line:7] - INFO: 這是一個info級別的日志信息
2019-02-13 20:41:33,080 - hello.py[line:8] - WARNING: 這是一個warning級別的日志信息
2019-02-13 20:41:33,080 - hello.py[line:9] - ERROR: 這是一個error級別的日志信息
2019-02-13 20:41:33,080 - hello.py[line:10] - CRITICAL: 這是一個critical級別的日志信息
代碼說明:
- level 表示設(shè)置的日志等級
- format 表示日志的輸出格式, 參數(shù)說明:
- %(levelname)s: 打印日志級別名稱
- %(filename)s: 打印當(dāng)前執(zhí)行程序名
- %(lineno)d: 打印日志的當(dāng)前行號
- %(asctime)s: 打印日志的時間
- %(message)s: 打印日志信息
日志信息保存到日志文件的示例代碼:
import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', filename="log.txt", filemode="w") logging.debug('這是一個debug級別的日志信息') logging.info('這是一個info級別的日志信息') logging.warning('這是一個warning級別的日志信息') logging.error('這是一個error級別的日志信息') logging.critical('這是一個critical級別的日志信息')
會在此目錄中自動生成log.txt文件,生成日志數(shù)據(jù)
運行結(jié)果:
2022-01-15 11:31:14,529 - web.py[line:59] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:31:22,542 - web.py[line:63] - INFO: 靜態(tài)資源請求:/df
2022-01-15 11:46:14,034 - web.py[line:60] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:46:14,036 - web.py[line:60] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:47:24,065 - web.py[line:60] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:47:26,655 - web.py[line:60] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:47:45,224 - web.py[line:75] - INFO: 靜態(tài)資源請求:/favicon.ico
2022-01-15 11:52:15,723 - web.py[line:60] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:52:23,513 - web.py[line:60] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:52:31,315 - web.py[line:60] - INFO: 動態(tài)資源請求:/index.html
2022-01-15 11:52:36,838 - web.py[line:75] - INFO: 靜態(tài)資源請求:/favicon.ico
logging日志在mini-web項目中應(yīng)用
web.py 程序使用logging日志示例:
1.程序入口模塊設(shè)置logging日志的設(shè)置
import socket import threading import sys import framework import logging # logging日志的配置 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', filename="log.txt", filemode="w")
2.INFO級別的日志輸出,示例代碼:
# 判斷是否是動態(tài)資源請求 if request_path.endswith(".html"): """這里是動態(tài)資源請求,把請求信息交給框架處理""" logging.info("動態(tài)資源請求:" + request_path) ... else: """這里是靜態(tài)資源請求""" logging.info("靜態(tài)資源請求:" + request_path) ...
3.WARNING級別的日志輸出,示例代碼:
# 獲取命令行參數(shù)判斷長度 if len(sys.argv) != 2: print("執(zhí)行命令如下: python3 xxx.py 9000") logging.warning("用戶在命令行啟動程序參數(shù)個數(shù)不正確!") return # 判斷端口號是否是數(shù)字 if not sys.argv[1].isdigit(): print("執(zhí)行命令如下: python3 xxx.py 9000") logging.warning("用戶在命令行啟動程序參數(shù)不是數(shù)字字符串!") return
framework.py 程序使用logging日志示例:
ERROR級別的日志輸出,示例代碼:
# 處理動態(tài)資源請求 def handle_request(env): # 獲取動態(tài)請求資源路徑 request_path = env["request_path"] print("接收到的動態(tài)資源請求:", request_path) # 遍歷路由列表,選擇執(zhí)行的函數(shù) for path, func in route_list: if request_path == path: result = func() return result else: logging.error("沒有設(shè)置相應(yīng)的路由:" + request_path) # 沒有找到動態(tài)資源 result = not_found() return result
說明:
- logging日志配置信息在程序入口模塊設(shè)置一次,整個程序都可以生效。
- logging.basicConfig 表示 logging 日志配置操作
小結(jié)
記錄python程序中日志信息使用 logging 包來完成
logging日志等級有5個:
- DEBUG
- INFO
- WARNING
- ERROR
- CRITICAL
打印(記錄)日志的函數(shù)有5個:
- logging.debug函數(shù), 表示: 打印(記錄)DEBUG級別的日志信息
- logging.info函數(shù), 表示: 打印(記錄)INFO級別的日志信息
- logging.warning函數(shù), 表示: 打印(記錄)WARNING級別的日志信息
- logging.error函數(shù), 表示: 打印(記錄)ERROR級別的日志信息
- logging.critical函數(shù), 表示: 打印(記錄)CRITICAL級別的日志信息
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
python 使用多線程創(chuàng)建一個Buffer緩存器的實現(xiàn)思路
這篇文章主要介紹了python 使用多線程創(chuàng)建一個Buffer緩存器的實現(xiàn)思路,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07python算法測試結(jié)果自動保存到excel表格的實現(xiàn)步驟
我們在進行算法評估是通常會針對每個樣本的算法處理結(jié)果進行統(tǒng)計,例如每個樣本正確預(yù)測數(shù)量、漏檢數(shù)量和誤檢數(shù)量、精度等,本文小編將給大家介紹python算法測試結(jié)果自動保存到excel表格的實現(xiàn)步驟,感興趣的朋友可以參考下2023-12-12python導(dǎo)出requirements.txt的幾種方法以及環(huán)境配置詳細流程
這篇文章主要給大家介紹了關(guān)于python導(dǎo)出requirements.txt的幾種方法以及環(huán)境配置詳細流程,requirements.txt 文件是一個文本文件,用于列出你的Python項目所依賴的軟件包及其版本,需要的朋友可以參考下2023-11-11python判斷列表字典字符串元組是否存在某個值或者空值(多種方法)
這篇文章主要介紹了python判斷列表字典字符串元組是否存在某個值或者空值,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-02-02