How to create a simple logger in Python, second part

As I explained in the first part of ‘How to create a simple logger’ in Python series, logging is a very important aspect of software development, especially for the professional software developer. Although a junior Python developer, there is a project which I am coding in which I need to make use of the Python’s logging builtin module.

As you may already know, for one to log their applications they need to make use of the Python’s builtin module called logging.

The piece of Python code being shown below, makes sure to import the Python’s logging module from the standard library.

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

import logging

In the first part, we managed to create a simple logger with the help of the Python’s builtin logging module. For now, our simple logger does some basic logging, so we need to customize it.

There are some problems with our basic logger. To truly understand these problems from a concrete perspective, let’s make use of it and create a new log file in our local operating system.

python hack_logging.py

Before executing the above command in your local terminal application, make sure to delete the old file which stores the logs.

The old log file should look like the one which is being shown below.

storelogs.log

Once we run the hack_logging.py module through our terminal application, a new storelogs.log file is going to be created in our local machine, a fresh one.

It is no different from the old log file. It’s content is being shown below.

INFO:root:This is some informational message
ERROR:root:This is an error log

What are some of the problems with our log file?

First of all, we don’t get the name of the application which is creating the logs, from the above output. Second, there is no information about the date during which each one of the logs has been created.

All the information we get from the current log file is the level of each log, and also its message.

What can we do to fix our custom logger so it can also log the date for each one of the logs?

Here it is the Python code we have for now

For now, our custom logger looks exactly like the code which is being shown below.

import logging
 
def main():
    logging.basicConfig(level=logging.INFO, filename='storelogs.log')
    logging.info('This is some informational message')
    logging.error('This is an error log') 

if __name__ == '__main__':
    main()    

The above code configures a simple logger through the logging.basicConfig builtin function. It does not specify the format of the log file.

Let’s customize the logger being shown above to log the date for each one of the logs and also the application from which they’re being logged.

Customize the simple logger to a more advanced one

The inner part of the main() function in our basic logger will change entirely. So lets’ start.

import logging
 
def main():
    pass

if __name__ == '__main__':
    main()  

The first thing which we have to do is to configure the logger with the name of the application.

def main():
    logger = logging.getLogger('mainApp')
    print(logger)

if __name__ == '__main__':
    main() 

Let’s execute the customized logger and see the results. Once I executed the hack_logging.py module with the help of the following command, I got no log file in the output.

python hack_logging.py

All I got was the following object.

<logging.Logger object at 0x10290b150>

There is a class called Logger inside the Python’s builtin logging module. You can easily notice it from the above object.

Let’s run this class in the interactive console through the Python’s builtin module.

logging.Logger()

Once I managed to run the above piece of Python code in my own operating system, I got the following error.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes at least 2 arguments (1 given)

As you can see from the above output being shown in the Python interactive shell, the logging.Logger class takes at least two arguments.

Let’s call the Python’s logging.Logger class again; this time with a string as an argument.

logging.Logger('mainApp')

The result of the above Python code is being shown below.

<logging.Logger object at 0x109032f90>

As you can see from the result being show above, the call to the logging.Logger class worked; no error was generated this time.

You can also access the attribute you gave it through the command which is being shown below.

logger = logging.Logger('mainApp')
logger.name

The result of the above Python code is being shown below.

mainApp

Long story short, we can also define our logger object by calling the class directly from the Python’s builtin logging module, instead of making use of the logging.getLogger builtin function.

logger = logging.Logger('mainApp')

If you want to create the main logger object by calling the logging.Logger class directly, your code should look like the one shown below.

def main():
    logger = logging.Logger('mainApp')
    print(logger)

if __name__ == '__main__':
    main() 

Let’s continue coding our custom logger application. We need to set the level of logging in our logger object.

We can easily check the default level of our current logger object by making use of the following statement.

logger.level

Let’s make use of the above statement in our script.

def main():
    logger = logging.Logger('mainApp')
    print(logger)
    print(logger.level)

if __name__ == '__main__':
    main() 

Execute the above script with the following command.

python hack_logging.py

Once the custom logger script got executed with the above command, the following result was produced.

<logging.Logger object at 0x100a74110>
0

So the level of logging equals to 0.

For the purpose of this tutorial, we are going to set the level of logging to logging.INFO. The logging.Logger object has a method called setLevel which can be utilized to set the level of logging.

import logging

def main():
    logger = logging.Logger('mainApp')
    logger.setLevel(logging.INFO)
    print(logger)
    print(logger.level)

if __name__ == '__main__':
    main() 

Let’s execute the custom logger again through the following command and check if the level of logging has changed or not.

python hack_logging.py

Once I executed the above piece of Python code I got the following output.

<logging.Logger object at 0x101875110>
20

As you can see from the above output, the level of logging has changed its numerical value, from 0 to 20.

Now we need to configure the file in which the logs are going to be stored. The class logging.FileHandler is going to help us to accomplish this task.

import logging

def main():
    logger = logging.Logger('mainApp')
    logger.setLevel(logging.INFO)
    print(logger)
    print(logger.level)

    # create a file handler
    fh = logging.FileHandler('customlogs.log')

if __name__ == '__main__':
    main() 

Now that we have configured a file to store our logs through the logging.FileHandler, we need to add our file handler object with the help of the following code.

logger.addHandler(fh)

Our script should look like the one being shown below.

import logging

def main():
    logger = logging.Logger('mainApp')
    logger.setLevel(logging.INFO)
    print(logger)
    print(logger.level)

    # create a file handler
    fh = logging.FileHandler('customlogs.log')
    logger.addHandler(fh)

if __name__ == '__main__':
    main() 

Let’s execute the above script through the following command and see what happens.

python hack_logging.py

Once I managed to run the above command, the following output got displayed on my terminal application.

20

Let’s see the customlogs.log file. Mine is empty; and yours should be too since we have not made use of any function part of the logging module such as logging.info, logging.debug, logging.error, logging.warning and logging.critical.

It is time to do some logging.

import logging

def main():
    logger = logging.Logger('mainApp')
    logger.setLevel(logging.INFO)
    print(logger)
    print(logger.level)

    # create a file handler
    fh = logging.FileHandler('customlogs.log')
    logger.addHandler(fh)

    logger.info('This is an informational message')

if __name__ == '__main__':
    main() 

Save the above script and run it with the help of the following command.

python hack_logging.py

Then check the content of the customlogs.log file again. If everything got executed properly, you should have the following content in your log file.

This is some informational message

As you can see from the above output, only the message of the log is being stored inside the customlogs.log file. There is no information on the log, such as the application it is coming from, the level and its date.

Final thoughts

You are going to learn how to create a formatter object for the file handler in the next part.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Leave a Reply

Your email address will not be published. Required fields are marked *