the singleton pattern this looks even better it is simple and cleanas each function does only one thing the write_log function just writes the message level and message text to the file each log writer simply calls the write_log functionadding the level of the message to the call ' sure you are really beginning to like our little loggerbut what bothers me most at the moment is that hardcoded filename log that we use to persist all our log files in you now know that logging makes you better developer and saves you lot of time sothis being such nice loggeryou are sure to want to use it in several of your own projects the last thing you want your logger to do is to write messages from different projects to the same file to circumvent this issuewe could just add the file name as parameter on the functions we call when logging our messages go ahead and implement this change note that the following code snippet is still incompleteas the write_log function still takes filename parameter logger py def write_log(filenamelevelmsg)with open(filename" "as log_filelog_file write("[{ }{ }\nformat(levelmsg)def critical(msg)write_log("critical",msgdef error(msg)write_log("error"msgdef warn(msg)write_log("warn"msgdef info(msg)write_log("info"msgdef debug(msg)write_log("debug"msgthe filename parameter does not change from call to callso passing the same value over and over is not the right way to do things the very reason we extracted the write_log function from the other functions is so that we would not have to repeat the same code we want to set up the logger oncewith the log file it should be logging toand then use it without paying any more attention to the selection of the file to write to