I managed to go an entire week without a Python related entry. Of course, despite this lots of things have been going on. I have a stack of potential blog entries metaphorically at my side, some of which may never see the light of day. But first the most important thing.
There is now a new version of StandOut in subversion :
StandOut 3.0.0 Alpha
There are also unit tests to go with it.
StandOut is a simple class that redirects sys.stdout and sys.stderr. This serves two purposes. By passing in a file name when you instantiate StandOut it can log everything printed (and all errors) to a file. You can also assign messages a priority, and tell StandOut what priority of messages to actually display, making implementing different "verbosity levels" very easy.
When I first wrote StandOut I thought I would use the verbosity features, but I didn't actually use them until recent changes in rest2web. I was amazed that it worked, and that it was easy to use. Unfortunately along the way, StandOut had grown lots of cruft and complicated ways of using it that nobody needed.
This version is a complete rewrite. It is much better written, with a simpler and straightforward API. It isn't compatible with the previous version, so programs currently using StandOut will need minor modifications to use the new version.
Enough prattle, here's how to use it.
By default StandOut diverts both stdout and stderr. If you pass in a filename (optional) then that will be used to log to. Output on stderr will be prefixed with "[err] " [1].
The log file will then contain :
hello [err] This is an error
The standout.close() call restores sys.stdout and sys.stderr to their normal state and closes the logfile. If an unhandled exception occurs during your code, execution will terminate. If you want to guarantee that close is still called, you can put it inside a try:... finally: block. Unfortunately the exception will then be raised (by the finally clause) after close has been called. You can use the following trick to get round this :
You will see that the error still appears in the logfile in the usual way. On the other hand, if you just let your program terminate (without trapping errors like this), then the open log file will be garbage collected and closed for you.
By default all messages have a priority of five. There are four possible output methods :
You can configure their threshold independently, but there are easier ways as well. If a message has a equal or higher priority than the threshold for an output method, it will be passed on. If the priority is lower than the threshold, it will be dropped. Easy hey.
The default threshold for the output stream and file is five. The default threshold for the error stream and file is zero (everything logged).
Unfortunately the message telling you that the priority is four won't be displayed because the threshold is too low.
Logged to the file will be :
[err] Error message with a priority of four Output message with a priority of six [err] Error message with a priority of six
There is also another way of setting the priority of individual messages, which you may prefer. This is what I used to implement varying levels of verbosity in rest2web.
Because we explicitly set the threshold for errors to five, only output and errors with a priority of five (or greater) will be passed on. The above code results in the following output :
Message with a priority of six [err] Error with a priority of six
The following properties (which can also be passed in as keyword arguments) are used to set different thresholds for the different output methods :
If the output methods have different thresholds, then standout.threshold (etc) will return -1.
There is currently no way of logging to a separate file for errors, other than instantiating StandOut twice :
I developed this using the test driven development methodolgy we use at work. This guides the development process and results in better code and a better API. Someday I may do a blog entry about it.
The result is an 8k module with 38k of tests. I'm sure the tests could be better factored, but I think the code is pretty good and well tested.
There are still a few questions before I do a final release :
I personally think that using two instances for separate logfiles is fine. This kind of answers questions one and two. I don't see the need for passing around open files, but it would make testing easier.
Anyway, feedback appreciated.
[1] | The final module will be called standout rather than standout3. The name is temporary to avoid clashes with the current standout module. You can change the error prefix by passing in a string with the errPrefix keyword. It defaults to "[err] ". |
Posted by Fuzzyman on 2006-06-18 18:07:18.
Categories:
Python, Projects
Visit the Voidspace Techie Blog to read this entry and more.