I'm trying to replace an ad-hoc logging system with Python's logging module. I'm using the logging system to output progress information for a long task on a single line so you can tail
the log or watch it in a console. I've done this by having a flag on my logging function which suppresses the newline for that log message and build the line piece by piece.
我正在尝试用Python的日志记录模块替换ad-hoc日志记录系统。我正在使用日志记录系统在一行中输出长任务的进度信息,因此您可以在日志中拖尾或在控制台中查看它。我通过在我的日志记录功能上设置一个标志来完成此操作,该标志会抑制该日志消息的换行符并逐段构建该行。
All the logging is done from a single thread so there's no serialisation issues.
所有日志记录都是从单个线程完成的,因此没有序列化问题。
Is it possible to do this with Python's logging module? Is it a good idea?
是否可以使用Python的日志记录模块执行此操作?这是个好主意吗?
3 个解决方案
#1
8
Let's start with your last question: No, I do not believe it's a good idea. IMO, it hurts the readability of the logfile in the long run.
让我们从你的最后一个问题开始:不,我不相信这是个好主意。 IMO,从长远来看,它会损害日志文件的可读性。
I suggest sticking with the logging module and using the '-f' option on your 'tail' command to watch the output from the console. You will probably end up using the FileHandler. Notice that the default argument for 'delay' is False meaning the output won't be buffered.
我建议坚持使用日志记录模块并使用'tail'命令中的'-f'选项来监视控制台的输出。您可能最终会使用FileHandler。请注意,'delay'的默认参数为False,表示不会缓冲输出。
If you really needed to suppress newlines, I would recommend creating your own Handler.
如果你真的需要压制换行符,我建议你创建自己的Handler。
#2
24
If you wanted to do this you can change the logging handler terminator. I'm using Python 3.4. This was introduced in Python 3.2 as stated by Ninjakannon.
如果要执行此操作,可以更改日志记录处理程序终止符。我正在使用Python 3.4。这是在Ninjakannon所说的Python 3.2中引入的。
handler = logging.StreamHandler()
handler.terminator = ""
When the StreamHandler writes it writes the terminator last.
当StreamHandler写入时,它最后写入终结符。
#3
12
The new line, \n
, is inserted inside the StreamHandler
class.
新行\ n被插入StreamHandler类中。
If you're really set on fixing this behaviour, then here's an example of how I solved this by monkey patching the emit(self, record)
method inside the logging.StreamHandler class.
如果你真的开始修复这个行为,那么这里是一个例子,说明我是如何通过修补logging.StreamHandler类中的emit(self,record)方法来解决这个问题的。
A monkey patch is a way to extend or modify the run-time code of dynamic languages without altering the original source code. This process has also been termed duck punching.
猴子补丁是一种扩展或修改动态语言的运行时代码而不改变原始源代码的方法。这个过程也被称为鸭子冲孔。
Here is the custom implementation of emit()
that omits line breaks:
这是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)
Then you would make a custom logging class (in this case, subclassing from TimedRotatingFileHandler
).
然后,您将创建一个自定义日志记录类(在本例中,从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)
Some people might argue that this type of solution is not Pythonic, or whatever. It might be so, so be careful.
有些人可能会争辩说这种解决方案不是Pythonic,或者其他什么。可能是这样,所以要小心。
Also, be aware that this will globally patch SteamHandler.emit(...)
, so if you are using multiple logging classes, then this patch will affect the other logging classes as well!
另外,请注意这将全局修补SteamHandler.emit(...),因此如果您使用多个日志记录类,那么此修补程序也将影响其他日志记录类!
Check out these for further reading:
查看这些内容以供进一步阅读:
- What is monkey-patching?
- Is monkeypatching considered good programming practice?
- Monkeypatching For Humans
什么是猴子补丁?
monkeypatching被认为是良好的编程习惯吗?
Monkeypatching为人类
Hope that helps.
希望有所帮助。
#1
8
Let's start with your last question: No, I do not believe it's a good idea. IMO, it hurts the readability of the logfile in the long run.
让我们从你的最后一个问题开始:不,我不相信这是个好主意。 IMO,从长远来看,它会损害日志文件的可读性。
I suggest sticking with the logging module and using the '-f' option on your 'tail' command to watch the output from the console. You will probably end up using the FileHandler. Notice that the default argument for 'delay' is False meaning the output won't be buffered.
我建议坚持使用日志记录模块并使用'tail'命令中的'-f'选项来监视控制台的输出。您可能最终会使用FileHandler。请注意,'delay'的默认参数为False,表示不会缓冲输出。
If you really needed to suppress newlines, I would recommend creating your own Handler.
如果你真的需要压制换行符,我建议你创建自己的Handler。
#2
24
If you wanted to do this you can change the logging handler terminator. I'm using Python 3.4. This was introduced in Python 3.2 as stated by Ninjakannon.
如果要执行此操作,可以更改日志记录处理程序终止符。我正在使用Python 3.4。这是在Ninjakannon所说的Python 3.2中引入的。
handler = logging.StreamHandler()
handler.terminator = ""
When the StreamHandler writes it writes the terminator last.
当StreamHandler写入时,它最后写入终结符。
#3
12
The new line, \n
, is inserted inside the StreamHandler
class.
新行\ n被插入StreamHandler类中。
If you're really set on fixing this behaviour, then here's an example of how I solved this by monkey patching the emit(self, record)
method inside the logging.StreamHandler class.
如果你真的开始修复这个行为,那么这里是一个例子,说明我是如何通过修补logging.StreamHandler类中的emit(self,record)方法来解决这个问题的。
A monkey patch is a way to extend or modify the run-time code of dynamic languages without altering the original source code. This process has also been termed duck punching.
猴子补丁是一种扩展或修改动态语言的运行时代码而不改变原始源代码的方法。这个过程也被称为鸭子冲孔。
Here is the custom implementation of emit()
that omits line breaks:
这是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)
Then you would make a custom logging class (in this case, subclassing from TimedRotatingFileHandler
).
然后,您将创建一个自定义日志记录类(在本例中,从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)
Some people might argue that this type of solution is not Pythonic, or whatever. It might be so, so be careful.
有些人可能会争辩说这种解决方案不是Pythonic,或者其他什么。可能是这样,所以要小心。
Also, be aware that this will globally patch SteamHandler.emit(...)
, so if you are using multiple logging classes, then this patch will affect the other logging classes as well!
另外,请注意这将全局修补SteamHandler.emit(...),因此如果您使用多个日志记录类,那么此修补程序也将影响其他日志记录类!
Check out these for further reading:
查看这些内容以供进一步阅读:
- What is monkey-patching?
- Is monkeypatching considered good programming practice?
- Monkeypatching For Humans
什么是猴子补丁?
monkeypatching被认为是良好的编程习惯吗?
Monkeypatching为人类
Hope that helps.
希望有所帮助。