0

Seeking for your advice, currently doing self studies regarding the Python Design Pattern. In chapter 2 I stock with this class. It has 2 module, logger_class.py and new_script_with_logger.py

for the module logger_class.py

class Logger(object):
    """A file-based message logger with the following properties
    Attributes:
        file_name: a string representing the full path of the log file to which this logger will write it messages
    """
    def __init__(self, file_name):
        """Return a logger object whose file_name is * file_name*"""
        self.file_name = file_name
    def _write_log(self, level, msg):
        """Writes a message to the file_name for a specific Logger instance"""
        with open(self.file_name, 'a') as log_file:
            log_file.write('[{0} {1}\n'.format(level, msg))
    def critical(self, level, msg):
        self._write_log('CRITICAL', msg)
    def error(self, level, msg):
        self._write_log(self, level, msg)
    def warn(self, level, msg):
        self._write_log('WARN', msg)
    def info(self, level, msg):
        self._write_log('INFO', msg)
    def debug(self, level, msg):
        self._write_log('DEBUG', msg)

And here the other module new_script_with_logger.py

from logger_class import Logger

logger_object = Logger('/var/log/class_logger.log')
logger_object.info('this is an info message')

The above code is came from the book of "Practical Python Design Patterns Pythonic Solution to Common Problems by Wessel Badenhorst"

When I run the code of new_script_with_logger.py, I got error message from PyCharm IDE In the console command running it

python new_script_with_logger.py

The result is like this

Traceback (most recent call last):
  File "C:\Users\Python Design Pattern\Practical_Design\Practical_Python_Design_PaTTERN\new_script_with_logger.py", line 4, in <module>
    logger_object.info('this is an info message')
TypeError: Logger.info() missing 1 required positional argument: 'msg'

I'm newbie please respect and understand my post thank you in advance

Explanation of how the code run

7
  • 2
    I'm surprised the Logger class was provided as is in the book, unless it is a typo. If you look at the class methods from critical to debug, it is clear that there shouldn't be the level parameter, as it is implicitly described in the name of the method (error means the log level is error, straightforward.) Basically, the right way to "debug" this code is to get rid of the level parameter in methods from critical to debug, so for example you should have the following header : def info(self, msg): That will do Commented Sep 19, 2024 at 8:39
  • Beside, there are other mistakes in the code your provided, such as in the error method. It should be calling the _write_log just like the other by doing self._write_log('ERROR', msg), and not like it is done, which is incorrect for several reason. Commented Sep 19, 2024 at 8:48
  • Hi @Lrx. I tried your advice by removing the level in the methods and I got a lot of error Commented Sep 19, 2024 at 9:02
  • Hi @Kram R, I added another comment, but I will provide you with a more detailed response to be as clear as possible. Commented Sep 19, 2024 at 9:06
  • @KramR Where did you copy that code from? It doesn't match the code examples from the book. The original examples can be found here. However, you should note carefully that the book you are studying is from 2017. This equates to version 3.6 of Python, which is no longer supported - so you might want to consider finding a more up to date resource to learn from. Commented Sep 19, 2024 at 9:31

1 Answer 1

1

There are multiple flaws in the definition of the Logger class.

How it is supposed to work

  • the _write_log method is supposed to work as an "abstract method", a generic method that is supposed to do the work of logging no matter the level and the message.
  • the other methods are here to provide some direct applications of the abstract method above. For example the info method is by nature forcing the level to be info.

The flaws

  • None of the "applications method" (from critical to debug) should have as an argument the log level, as they already define it by construction.
  • The error method is also wrong in the way it calls the _write_log with a generic level, (and the self argument at the beginning is redundant)

'Correct' version

Here is a revised version of the code you provided:

class Logger(object):
    """A file-based message logger with the following properties
    Attributes:
        file_name: a string representing the full path of the log file to which this logger will write it messages
    """
    def __init__(self, file_name):
        """Return a logger object whose file_name is * file_name*"""
        self.file_name = file_name
    def _write_log(self, level, msg):
        """Writes a message to the file_name for a specific Logger instance"""
        with open(self.file_name, 'a') as log_file:
            log_file.write('[{0}] {1}\n'.format(level, msg))
    def critical(self, msg):
        self._write_log('CRITICAL', msg)
    def error(self, msg):
        self._write_log('ERROR', msg)
    def warn(self, msg):
        self._write_log('WARN', msg)
    def info(self, msg):
        self._write_log('INFO', msg)
    def debug(self, msg):
        self._write_log('DEBUG', msg)

Now you can see that there is a consistent use of the _write_log accross every application below it. If you have more question feel free to ask them in comments

Sign up to request clarification or add additional context in comments.

1 Comment

Hi Lrx, thank you for correcting the code, I will study your code.. .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.