DEV Community

Cover image for Implementing logging in Python via decorators

Posted on


Implementing logging in Python via decorators

Disclaimer: This is my first article. I will try to post once in a while if I think any article might help someone.
Personally, I hate buzzwords so I will try to keep it simple. Suggestions are welcome.

Writing logs for your program is one of the most crucial thing in software development. It helps to find bugs, write analytics, keep a track of traffic, verify if there is any DDoS attack in your server, etc.

Personally, as a person who never had a mentor and learned myself to code, I have always struggled how to maintain a clean code in my projects. So, in order to avoid writing many try... catch... clauses in every function I though if I write a decorator where I catch the error and log it in a .log file.

UPDATE: There is a typo in the flowchart. It should be Throw Exception. My apologies.

Python Log

First we create a file named (or whatever name you want). Here we will write the log decorator.

import logging
import functools

def _generate_log(path):
    Create a logger object
    :param path: Path of the log file.
    :return: Logger object.
    # Create a logger and set the level.
    logger = logging.getLogger('LogError')

    # Create file handler, log format and add the format to file handler
    file_handler = logging.FileHandler(path)

    # See
    # for log format attributes.
    log_format = '%(levelname)s %(asctime)s %(message)s'
    formatter = logging.Formatter(log_format)

    return logger

def log_error(path='<path>/log.error.log'):
    We create a parent function to take arguments
    :param path:

    def error_log(func):

        def wrapper(*args, **kwargs):

                # Execute the called function, in this case `divide()`.
                # If it throws an error `Exception` will be called.
                # Otherwise it will be execute successfully.
                return func(*args, **kwargs)
            except Exception as e:
                logger = _generate_log(path)
                error_msg = 'And error has occurred at /' + func.__name__ + '\n'

                return e  # Or whatever message you want.

        return wrapper

    return error_log

Enter fullscreen mode Exit fullscreen mode

Now, we create another Python file. Let's call it Here we create a function called divide() which divides two numbers.

def divide(num1, num2):
    return num1 / num2

if __name__ == '__main__':
    result = divide(10, 0)
Enter fullscreen mode Exit fullscreen mode

But when we execute this code, the error message will be shown in console and not in a log file. In order to add logging in this function we import module and call log_error() function as a decorator.

import log

def divide(num1, num2):
    return num1 / num2

if __name__ == '__main__':
    result = divide(10, 0)
Enter fullscreen mode Exit fullscreen mode

After we run this code, a log file will be created based on the path that you added and inside that file the error log will be appended.

ERROR 2020-02-20 14:39:56,233 And error has occurred at /divide
Traceback (most recent call last):
  File "<path>/", line 44, in wrapper
    return func(*args, **kwargs)
  File "<path>/", line 6, in divide
    return num1 / num2
ZeroDivisionError: division by zero
Enter fullscreen mode Exit fullscreen mode

Now, every time we create a function, we can add @log.log_error() decorator and all the error logs will be appended in that file.

Oldest comments (0)

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.