Why We Should Write the Logging Module into Class
Introduction
Object-oriented programming (OOP) is a programming paradigm that is based on the concept of "objects", which can contain data and code that manipulates that data. In Python, a class is a blueprint for creating objects. It defines the attributes (properties) and behaviors (methods) that the objects of the class will have.
Writing the logging module as a class has several benefits:
- Encapsulation: By encapsulating the logging functionality within a class, you can hide the implementation details from the rest of the program, allowing you to change the implementation without affecting the rest of the program.
- Reusability: If you write the logging module as a class, you can easily reuse it in other projects by simply creating an instance of the class and calling its methods. This is more efficient than copying and pasting code from one project to another.
- Extension: If you need to add additional functionality to the logging module, you can do so by creating a subclass of the original logging class and adding the new methods and attributes to the subclass.
- Modularity: By writing the logging module as a class, you can separate the logging functionality from the rest of the program, which can make the program easier to understand and maintain.
Here is why should we write logger as class
Β
What weβre handle in logging module
There are several common attributes that you might use in the logging module:
- Message code: A message code is a short, unique identifier for a log message. You can use message codes to quickly identify specific log messages in a large log file.
- Message ID: A message ID is a unique identifier for a log message that is generated automatically by the logging module. You can use message IDs to track log messages over time and across different systems.
- Logging callbacks: A logging callback is a function that is called whenever a log message is emitted. You can use logging callbacks to perform additional processing on log messages, such as sending an email or storing the log message in a database.
- Handlers: Handlers are responsible for routing log messages to the appropriate destination. The logging module provides several built-in handlers, such as StreamHandler (for logging to the console), FileHandler (for logging to a file), and SMTPHandler (for logging to an email server). You can use these handlers to customize where log messages are sent.
Use cases:
- Multi-language logging: If your application supports multiple languages, you may want to log messages in different languages depending on the user's preferred language. You can use the logging module's internationalization features to support multi-language logging.
- Changing the logging end-point: You might want to change the logging end-point if you want to send log messages to a different destination. For example, you might want to change the logging end-point from a local file to a cloud storage service like Amazon S3 or Google Cloud Storage. You can do this by changing the logging handler to a handler that is capable of sending log messages to the desired end-point.
- Changing the logging message: You might want to change the logging message if you want to modify the content of the message or the way it is formatted. For example, you might want to add additional information to the message, or change the message template to use a different formatting style. You can do this by modifying the message template or the
msg
attribute of theLogRecord
class.
- Changing the logging ID: You might want to change the logging ID if you want to track log messages using a different identifier. For example, you might want to change the logging ID from a simple sequential number to a more complex identifier that includes additional information about the log message. You can do this by modifying the
msg
attribute of theLogRecord
class or themessage_id
attribute of theLogger
class.
Logging module as we know
import logging logger = logging.getLogger(__name__) def do_something(): logger.debug("Doing something") try: # Do something that might fail except Exception as e: logger.exception("An error occurred while doing something")
In Scale, we should do:
In message_define.py file
from logging import ERROR, DEBUG, INFO D_COMN_01 = ("D_COMN_01", "Process '{process_name}' elapsed: {elapsed_time}s", DEBUG) D_COMN_02 = ("D_COMN_02", "'{result}' = {value} is not a valid result", ERROR) D_COMN_03 = ("D_COMN_03", "'{name}' has shape of {shape}", INFO)
Β
Write logger as a class:
Β
class ZLogger(logging.Logger): def __init__(self, name: str, level: int = logging.NOTSET): super().__init__(name, level) # Add cloud logging handler self.__add_cloud_logging_handler() # Add AWS logging handler self.__add_aws_logging_handler() def log_elapsed_time(self, process_name: str, elapsed_time: float): """ Log elapsed time for a process. Args: process_name(str): Name of the process elapsed_time(float): Elapsed time in seconds """ self.__do_log(*D_COMN_01, process_name=process_name, elapsed_time=elapsed_time) def log_invalid_result(self, result: str, value: any): """ Log an invalid result. Args: result(str): Name of the result value(any): Value of the result """ self.__do_log(*D_COMN_02, result=result, value=value) def log_shape(self, name: str, shape: tuple): """ Log the shape of an object. Args: name(str): Name of the object shape(tuple): Shape of the object """ self.__do_log(*D_COMN_03, name=name, shape=shape) def __do_log(self, code: str, template: str, level: int, **kwargs): message = template.format(**kwargs) full_message = f"{code}: {message}" self.log(level, full_message) def __add_cloud_logging_handler(self): """ Add a handler for logging to a cloud service. """ # Implementation details for adding a cloud logging handler def __add_aws_logging_handler(self): """ Add a handler for logging to Amazon Web Services (AWS). """ # Implementation details for adding an AWS logging handler
Benefits of Writing the Logging Module as a Class
Encapsulating the logging functionality in a custom logger class can help you create a more organized, efficient, and maintainable logging system for your application. By providing specific methods for logging common messages, you can enforce a consistent style and structure for log messages, which can make it easier to read and interpret log messages. You can also add docstrings to the methods in the custom logger class to provide clear documentation for how to use the logging functionality.
Using a custom logger class can also improve the separation of concerns between the application layer and the platform layer in your application. The application layer developers can focus on the business logic of the application, and they can use the custom logger class to log messages at the appropriate level of severity. The platform layer developers can then focus on how the log messages are displayed, routed, and stored, without having to worry about the specifics of the application logic.
Here is an example of how you might use a custom logger class in your application:
Β
To use the
ZLogger
class in your application, you can create an instance of the class and call its methods as needed:Example:
Case: project need to add log elapsed time of a function.
In file : function_1_1.py
Sample 2: Using Logger class
logger = ZLogger("my_logger") def function_1_1(): # do your logic logger.log_elapsed_time(process_name="process1", elapsed_time=123.45)
Β
Sample 1: Direct python logging module
logger = logging.Loger() # basic python loger def function_1_1(): # do your logic code,message_template,level = D_COMN_01 message_template.format(process_name="process1", elapsed_time=123.45) logger.log(level, f'{code}:{message})
Β
Compare
Here is a comparison of the benefits and drawbacks of using a custom logger class like
ZLogger
(Sample 1) versus using the basic logging.Loger
class (Sample 2) for logging in your application:Benefits of Sample 1 (custom logger class):
- Maintainability: Encapsulating the logging functionality in a separate class allows you to hide the implementation details from the rest of the program, making it easier to change the logging module without affecting the rest of the application.
- Documentation: Adding docstrings to the methods in the custom logger class provides clear documentation for how to use the logging functionality, helping other developers understand how to use the logging module and avoid common mistakes.
- Control: Providing specific methods for logging common messages enforces a consistent style and structure for log messages, making them easier to read and interpret, and helping you quickly identify specific log messages in a large log file.
- Reusability: Encapsulating the logging functionality in a separate class allows you to reuse the same logging code in multiple places throughout your application, helping you avoid duplicating code and making it easier to maintain the logging system as your application evolves.
Drawbacks of Sample 2 (basic logger class):
- Maintainability: Not encapsulating the logging functionality in a separate class exposes the implementation details to the rest of the program, making it harder to change the logging module without affecting the rest of the application.
- Documentation: Not providing any documentation for how to use the logging functionality makes it harder for other developers to understand how to use the logging module and avoid common mistakes.
- Control: Not enforcing a consistent style and structure for log messages makes it harder to read and interpret log messages, and also makes it more difficult to quickly identify specific log messages in a large log file.
- Reusability: Not encapsulating the logging functionality in a separate class prevents you from reusing the same logging code in multiple places throughout your application, leading to duplicated code and making it harder to maintain the logging system as your application evolves.
I hope this comparison helps you understand the benefits and drawbacks of using a custom logger class like
ZLogger
versus using the basic logging.Loger
class for logging in your application.In summary, using a custom logger class like
ZLogger
provides a more organized, efficient, and maintainable approach to logging, as it allows you to centralize the logging functionality in one place, enforce a consistent style and structure for log messages, and reuse the same logging code throughout your application. This can help you create a more robust, scalable, and maintainable logging system for your application.On the other hand, using the basic
logging.Loger
class does not provide the same level of organization, efficiency, and maintainability as using a custom logger class. It exposes the implementation details to the rest of the program, does not provide any documentation for how to use the logging functionality, does not enforce a consistent style and structure for log messages, and does not allow you to reuse the same logging code throughout your application.Overall, it is generally a good idea to use a custom logger class like
ZLogger
in your application to improve the organization, efficiency, and maintainability of your logging system.Β
Conclusion
It is generally easier to use the basic
logging
module directly when working on a small application. This is because the basic logging
module provides a simple and straightforward way to add logging to your application, and it does not require any additional setup or configuration.However, as your application grows in size or the number of developers working on the application increases, it may become more beneficial to use a custom logger class like
ZLogger
(Logger as a class ) to manage your logging system. This is because using a custom logger class can provide additional benefits such as better maintainability, documentation, control, and reusability, which can help you create a more robust, scalable, and maintainable logging system as your application grows.Ultimately, the decision to use a custom logger class or the basic
logging
module will depend on the specific needs and goals of your application. If you are working on a small application that does not require advanced logging functionality, the basic logging
module may be sufficient. However, if you are working on a larger application or have specific requirements for your logging system, using a custom logger class like ZLogger
may be a better choice.