CMSC 14100 — Lecture 26

Logging

In this class, you may have been using a fairly rudimentary approach to figuring out what your code is doing: inserting a bunch of print statements that produce the values you're interested in inspecting. This is a handy, low-cost way to get information, but it becomes cumbersome as your programs get larger. What we would like is a way to get the same information, but maybe not so tightly coupled to what the program may be doing at that point.

This is the idea behind logging: take all the information you'd get from prints but more controlled, and siphoned away into one convenient place, like a file.

Of course, there is a module that takes care of this kind of thing for us—logging.

Why is there an entire module for this? One of the things you may have realized when debugging your progrmas is that there can be a lot of information. Sometimes, it's useful, sometimes it isn't, and sometimes it can be useful but not at the moment, and so on. One very useful thing the logging module can do is attach levels to some of the information you want to produce.

Level Purpose
debug debugging (i.e. when you're actively hunting down a bug)
info informational
warning as a warning, when something might go wrong
error when something goes wrong
critical when something goes very wrong

This control allows you to see the relevant information. Perhaps you just want to know that your program is doing what it's meant to do, so you can filter out anything that's super detailed. But there will be messages that you definitely want to grab your attention when something goes very wrong.


    import logging
    logging.warning("This is a warning")
    logging.info("This is a information")
    

By default, logging messages get printed, but only for levels WARNING and above. But we can change these things by configuring the logger.


    import logging
    logging.basicConfig(filename="example.log", level=logging.INFO)
    logging.debug("This doesn't go into the log")
    logging.info("But this does go into the log file")
    logging.warning("And so does this")
    logging.error("And so does this")
    logging.critical("👍")
    

Finally, one can change how logging messages are written. For example, the current scheme just shows us the message and the name of the logger (if you're using more than one, for example, for different parts of a system), which is root by default. Usually, it's a good idea to include when a message was created by including the timestamp.


    import logging
    logging.basicConfig(format='%(asctime)s %(message)s')
    logging.warning('is when this event was logged.')
    logging.critical('uh oh')
    

Here, this tells the logger to format messages so that they are the timestamp specified by %(asctime)s followed by the message we provide, specified by %(message)s. There are lots of other options—for example, you may want to know the user that's running your program or the IP address of the computer that ran it.

This was just a really quick rundown of this tool. To learn more about how to use it in more detail, you can look up the logging package documentation.