Stop using print, start using loguru in Python

Yes, I know that the easiest way to receive some output from my Python script is to use a print statement. Nice and easy. But is it?

It can be a useful and quick solution if you are implementing a simple script. You will use it a few times and never get back to it. In such a case, a print statement can be good enough. One way or another, it still comes with a few drawbacks:

  • each output looks the same (let’s face it – it is ugly and it’s hard to read)
  • it is sent to standard output
  • it gives no information on a position in the code

Why loguru?

There are various logger libraries, but I’m a fan of loguru. Maybe it is because it was the first one I met? I like it a lot because it has features I like:

  • it is extremally easy to use
  • you can direct your logs to various outputs
  • gives you different log message looks on different occasions
  • informs you about the position in the code and the date/time of the message

Installation

In order to use loguru, you have to install it. It is dead simple, as you may imagine:

pip install loguru

Basic usage

So, it is installed, let’s see how it works. Here is the piece of code:

from loguru import logger

logger.info("Info text sample")
logger.error("Error text sample")
logger.debug("Debug message sample")

As the result, you will see something like this:

Each type of message is colored differently, it also gives clear information on the date and time and the place in the code given message was triggered.

One of the features I use often, is the possibility to save log messages also to the file. You can simply declare a different destination like this:

logger.add("my_log_file.log", rotation="10 MB")
// or
logger.add("my_log_file.log", rotation="1 week")

The first one creates the log file that will be replaced with the new one once it reaches 10 MB of size, the second one will rotate the file every week. Handy, isn’t it?

Of course, it can also be used to print variables:

from loguru import logger

my_list = [1, 2, 3, 'a', 'b', 'c']

logger.info(my_list)

my_variable = {
    'a': 'b',
    'c': 12345,
    'd': [1, 2, 3, 4],
    'e': my_list
}

logger.info(my_variable)

The killer feature

There is a lot of things you can do with loguru. My goal is not to show them all, but to convince you to use a logger library instead of print statements. For me, the killer feature of loguru is the ability to catch errors in the whole script. Yes, you can add it in one place and catch the error that occurred in any place. See the example:

from loguru import logger

my_list = [1, 2, 3]
my_variable = {
    'a': 'b'
}

def function_with_error(x, y):
    z = x + y
    return z

@logger.catch
def main():
    function_with_error(my_list, my_variable)

if __name__ == "__main__":
    main()

The thing you should pay attention to is the @logger.catch decorator just before the main function definition. It is where the magic occurs. Loguru is now catching all errors in the main function and in all nested functions. Here is the result of the above code:

Take a look at this output. It gives you so much information on what happened – what were the variables passed to the function, what is the error that occurred, in which line, what is the stack trace… And again – it can be saved in the file, so you will no longer need to guess what happened when your overnight script failed. I like it so much!