我正在尝试用Python的日志记录模块替换ad-hoc日志记录系统.我正在使用日志记录系统在一行中输出长任务的进度信息,以便您可以tail
在控制台中记录或查看它.我通过在我的日志记录功能上设置一个标志来完成此操作,该标志会抑制该日志消息的换行符并逐个构建该行.
所有日志记录都是从一个线程完成的,因此没有序列化问题.
是否可以使用Python的日志模块执行此操作?这是个好主意吗?
jus*_*gel 36
如果要执行此操作,可以更改日志记录处理程序终止符.我正在使用Python 3.4.这是在Ninjakannon所说的Python 3.2中引入的.
handler = logging.StreamHandler()
handler.terminator = ""
Run Code Online (Sandbox Code Playgroud)
当StreamHandler写入时,它最后写入终结符.
pja*_*ama 11
新行将\n
插入到StreamHandler
类中.
如果你真的在设置固定这种行为,那么这里的我是如何解决这个通过一个例子猴子打补丁的emit(self, record)
的logging.StreamHandler类中的方法.
猴子补丁是一种扩展或修改动态语言的运行时代码而不改变原始源代码的方法.这个过程也被称为鸭子冲孔.
以下是emit()
省略换行符的自定义实现:
def customEmit(self, record):
# Monkey patch Emit function to avoid new lines between records
try:
msg = self.format(record)
if not hasattr(types, "UnicodeType"): #if no unicode support...
self.stream.write(msg)
else:
try:
if getattr(self.stream, 'encoding', None) is not None:
self.stream.write(msg.encode(self.stream.encoding))
else:
self.stream.write(msg)
except UnicodeError:
self.stream.write(msg.encode("UTF-8"))
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
Run Code Online (Sandbox Code Playgroud)
然后,您将创建一个自定义日志记录类(在本例中,从子类化TimedRotatingFileHandler
).
class SniffLogHandler(TimedRotatingFileHandler):
def __init__(self, filename, when, interval, backupCount=0,
encoding=None, delay=0, utc=0):
# Monkey patch 'emit' method
setattr(StreamHandler, StreamHandler.emit.__name__, customEmit)
TimedRotatingFileHandler.__init__(self, filename, when, interval,
backupCount, encoding, delay, utc)
Run Code Online (Sandbox Code Playgroud)
有些人可能会说这种解决方案不是Pythonic,或者其他什么.可能是这样,所以要小心.
另外,请注意这将全局修补SteamHandler.emit(...)
,因此如果您使用多个日志记录类,那么此修补程序也将影响其他日志记录类!
查看这些内容以供进一步阅读:
希望有所帮助.
小智 11
Python 3.5.9
class MFileHandler(logging.FileHandler):
"""Handler that controls the writing of the newline character"""
special_code = '[!n]'
def emit(self, record) -> None:
if self.special_code in record.msg:
record.msg = record.msg.replace( self.special_code, '' )
self.terminator = ''
else:
self.terminator = '\n'
return super().emit(record)
Run Code Online (Sandbox Code Playgroud)
然后
fHandler = MFileHandler(...)
Run Code Online (Sandbox Code Playgroud)
例子:
# without \n
log.info( 'waiting...[!n]' )
...
log.info( 'OK' )
# with \n
log.info( 'waiting...' )
...
log.info( 'OK' )
Run Code Online (Sandbox Code Playgroud)
日志.txt:
waiting...OK
waiting...
OK
Run Code Online (Sandbox Code Playgroud)
让我们从你的最后一个问题开始:不,我不相信这是个好主意.IMO,从长远来看,它会损害日志文件的可读性.
我建议坚持使用日志记录模块并使用'tail'命令中的'-f'选项来监视控制台的输出.您可能最终会使用FileHandler.请注意,'delay'的默认参数为False,这意味着输出不会被缓冲.
如果你真的需要压制换行符,我建议你创建自己的Handler.