python 日志不会按照日期分割_python日志按天分割(多进程)

如果直接使用TimedRotatingFileHandler做日志分割,Python多进程启动时,会出现下面错误日志

错误日志

PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。: 'E:\\logs\\contest\\contest.log' -> 'E:\\logs\\contest\\contest.log.1'

python 原生logging日志模块可以满足大部分需求,但是唯独不适合多进程下日志切割。

该文章主要针对logging模块中的TimedRotatingFileHandler做的重写,代码如下:

import os

import re

import datetime

import logging

try:

import codecs

except ImportError:

codecs = None

class MultiprocessHandler(logging.FileHandler):

"""支持多进程的TimedRotatingFileHandler"""

def __init__(self,filename,when='D',backupCount=0,encoding=None,delay=False):

"""filename 日志文件名,when 时间间隔的单位,backupCount 保留文件个数

delay 是否开启 OutSteam缓存

True 表示开启缓存,OutStream输出到缓存,待缓存区满后,刷新缓存区,并输出缓存数据到文件。

False表示不缓存,OutStrea直接输出到文件"""

self.prefix = filename

self.backupCount = backupCount

self.when = when.upper()

# 正则匹配 年-月-日

self.extMath = r"^\d{4}-\d{2}-\d{2}"

# S 每秒建立一个新文件

# M 每分钟建立一个新文件

# H 每天建立一个新文件

# D 每天建立一个新文件

self.when_dict = {

'S':"%Y-%m-%d-%H-%M-%S",

'M':"%Y-%m-%d-%H-%M",

'H':"%Y-%m-%d-%H",

'D':"%Y-%m-%d"

}

#日志文件日期后缀

self.suffix = self.when_dict.get(when)

if not self.suffix:

raise ValueError(u"指定的日期间隔单位无效: %s" % self.when)

#拼接文件路径 格式化字符串

self.filefmt = os.path.join("logs","%s.%s" % (self.prefix,self.suffix))

#使用当前时间,格式化文件格式化字符串

self.filePath = datetime.datetime.now().strftime(self.filefmt)

#获得文件夹路径

_dir = os.path.dirname(self.filefmt)

try:

#如果日志文件夹不存在,则创建文件夹

if not os.path.exists(_dir):

os.makedirs(_dir)

except Exception:

print(u"创建文件夹失败")

print(u"文件夹路径:" + self.filePath)

pass

if codecs is None:

encoding = None

logging.FileHandler.__init__(self,self.filePath,'a+',encoding,delay)

def shouldChangeFileToWrite(self):

"""更改日志写入目的写入文件

:return True 表示已更改,False 表示未更改"""

#以当前时间获得新日志文件路径

_filePath = datetime.datetime.now().strftime(self.filefmt)

#新日志文件日期 不等于 旧日志文件日期,则表示 已经到了日志切分的时候

# 更换日志写入目的为新日志文件。

#例如 按 天 (D)来切分日志

# 当前新日志日期等于旧日志日期,则表示在同一天内,还不到日志切分的时候

# 当前新日志日期不等于旧日志日期,则表示不在

#同一天内,进行日志切分,将日志内容写入新日志内。

if _filePath != self.filePath:

self.filePath = _filePath

return True

return False

def doChangeFile(self):

"""输出信息到日志文件,并删除多于保留个数的所有日志文件"""

#日志文件的绝对路径

self.baseFilename = os.path.abspath(self.filePath)

#stream == OutStream

#stream is not None 表示 OutStream中还有未输出完的缓存数据

if self.stream:

#flush close 都会刷新缓冲区,flush不会关闭stream,close则关闭stream

#self.stream.flush()

self.stream.close()

#关闭stream后必须重新设置stream为None,否则会造成对已关闭文件进行IO操作。

self.stream = None

#delay 为False 表示 不OutStream不缓存数据 直接输出

# 所有,只需要关闭OutStream即可

if not self.delay:

#这个地方如果关闭colse那么就会造成进程往已关闭的文件中写数据,从而造成IO错误

#delay == False 表示的就是 不缓存直接写入磁盘

#我们需要重新在打开一次stream

#self.stream.close()

self.stream = self._open()

#删除多于保留个数的所有日志文件

if self.backupCount > 0:

print('删除日志')

for s in self.getFilesToDelete():

print(s)

os.remove(s)

def getFilesToDelete(self):

"""获得过期需要删除的日志文件"""

#分离出日志文件夹绝对路径

#split返回一个元组(absFilePath,fileName)

#例如:split('I:\ScripPython\char4\mybook\util\logs\mylog.2017-03-19)

#返回(I:\ScripPython\char4\mybook\util\logs, mylog.2017-03-19)

# _ 表示占位符,没什么实际意义,

dirName,_ = os.path.split(self.baseFilename)

fileNames = os.listdir(dirName)

result = []

#self.prefix 为日志文件名 列如:mylog.2017-03-19 中的 mylog

#加上 点号 . 方便获取点号后面的日期

prefix = self.prefix + '.'

plen = len(prefix)

for fileName in fileNames:

if fileName[:plen] == prefix:

#日期后缀 mylog.2017-03-19 中的 2017-03-19

suffix = fileName[plen:]

#匹配符合规则的日志文件,添加到result列表中

if re.compile(self.extMath).match(suffix):

result.append(os.path.join(dirName,fileName))

result.sort()

#返回 待删除的日志文件

# 多于 保留文件个数 backupCount的所有前面的日志文件。

if len(result) < self.backupCount:

result = []

else:

result = result[:len(result) - self.backupCount]

return result

def emit(self, record):

"""发送一个日志记录

覆盖FileHandler中的emit方法,logging会自动调用此方法"""

try:

if self.shouldChangeFileToWrite():

self.doChangeFile()

logging.FileHandler.emit(self,record)

except (KeyboardInterrupt,SystemExit):

raise

except:

self.handleError(record)

使用方法:

# -*- coding: utf-8 -*-

# @Time : 2019/6/24 12:59

# @Author : P0088599

import logging

from libs.multiprocess_log_handler import MultiprocessHandler

import sys

import os

logger = logging.getLogger()

# 定义日志输出格式

formattler = '%(asctime)s - thread-%(thread)-8d - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s'

fmt = logging.Formatter(formattler)

# 设置handleer日志处理器,日志具体怎么处理都在日志处理器里面定义

# SteamHandler 流处理器,输出到控制台,输出方式为stdout

# StreamHandler默认输出到sys.stderr

# 设置handler所处理的日志级别。

# 只能处理 >= 所设置handler级别的日志

# 设置日志输出格式

stream_handler = logging.StreamHandler(sys.stdout)

stream_handler.setLevel(logging.ERROR)

stream_handler.setFormatter(fmt)

# 使用我们写的多进程版Handler理器,定义日志输出到mylog.log文件内

# 文件打开方式默认为 a

# 按分钟进行日志切割

log_name = "logger"

file_handler = MultiprocessHandler(log_name, when='M')

file_handler.setLevel(logging.DEBUG)

file_handler.setFormatter(fmt)

# flask集成对logger增加handler日志处理器

logger.addHandler(stream_handler)

logger.addHandler(file_handler)

logger.info("this is a info log")

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中使用FFmpeg进行多进程分割视频文件可以通过以下步骤实现: 1. 首先,你需要安装FFmpeg并确保它已经添加到系统的环境变量中。你可以从FFmpeg的官方网站(https://ffmpeg.org/)下载并安装它。 2. 在Python中,你可以使用`subprocess`模块来执行FFmpeg命令。首先,导入`subprocess`模块: ```python import subprocess ``` 3. 接下来,你可以使用`subprocess.Popen`函数来启动一个新的进程并执行FFmpeg命令。例如,你可以使用以下代码来分割视频文件: ```python def split_video(input_file, output_file, start_time, duration): command = ['ffmpeg', '-i', input_file, '-ss', start_time, '-t', duration, '-c', 'copy', output_file] process = subprocess.Popen(command) process.wait() ``` 在上面的代码中,`input_file`是输入视频文件的路径,`output_file`是输出视频文件的路径,`start_time`是分割开始的间(以秒为单位),`duration`是分割的持续间(以秒为单位)。 4. 如果你想要同分割多个视频文件,你可以使用Python多进程库(如`multiprocessing`)来实现并行处理。以下是一个示例代码: ```python import multiprocessing def split_video(input_file, output_file, start_time, duration): # 分割视频的代码 if __name__ == '__main__': input_files = ['video1.mp4', 'video2.mp4', 'video3.mp4'] output_files = ['output1.mp4', 'output2.mp4', 'output3.mp4'] start_times = [10, 20, 30] durations = [5, 10, 15] processes = [] for i in range(len(input_files)): process = multiprocessing.Process(target=split_video, args=(input_files[i], output_files[i], start_times[i], durations[i])) processes.append(process) process.start() for process in processes: process.join() ``` 在上面的代码中,`input_files`是输入视频文件的路径列表,`output_files`是输出视频文件的路径列表,`start_times`是分割开始的间列表,`durations`是分割的持续间列表。通过循环创建多个进程来同处理多个视频文件分割操作。 这样,你就可以使用FFmpeg和Python多进程库来实现多进程分割视频文件了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值