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

