I am trying to create a class
that can create multiple instances of logging with saved .log
.
This is my code:
import logging
from datetime import datetime
import sys
import os
class DummyLog:
def __init__(self,
log_name: str = datetime.now().strftime('%d_%m_%Y__%H_%M_%S'),
logging_level: str = 'debug',
string_format: str = '%(asctime)s: %(levelname)s: %(message)s',
datetime_format: str = '%m/%d/%Y %I:%M:%S %p',
log_on_folder: bool = True,
log_folder_name: str = 'logs'
):
self.logName = log_name
self.logger = None
self.loggingLevel = logging_level
self.stringFormat = string_format
self.datetimeFormat = datetime_format
if log_on_folder:
if not os.path.exists(log_folder_name):
os.mkdir(log_folder_name)
self.logName = log_folder_name '/' self.logName
self.initiateLogger()
def initiateLogger(self):
""" This function will initiate the logger as a single threaded log"""
self.logger = logging.getLogger(self.logName)
if self.loggingLevel == 'debug':
self.loggingLevel = logging.DEBUG
self.logger.setLevel(self.loggingLevel)
logFormat = logging.Formatter(self.stringFormat, datefmt=self.datetimeFormat)
# Creating and adding the console handler
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(logFormat)
self.logger.addHandler(consoleHandler)
# Creating and adding the file handler
fileHandler = logging.FileHandler(self.logName ".log", mode='w')
fileHandler.setFormatter(logFormat)
self.logger.addHandler(fileHandler)
dl = DummyLog()
dl.logger.info("hi")
import time
time.sleep(1)
dl1 = DummyLog()
dl1.logger.info("hi")
When I run the above code, it creates only one .log
file and both the dl
and dl1
objects are being logged on the same .log
file.
The console output is printing the log
3 times instead of 2 times:
01/03/2022 12:01:20 PM: INFO: hi
01/03/2022 12:01:21 PM: INFO: hi
01/03/2022 12:01:21 PM: INFO: hi
but I have initiated the class Dummylog
two times. I am expecting the code change where the class DummyLog
can be called at multiple instances and each instance will save an individual .log
file.
I know I am missing something in the Handler
, but nothing is helping me to come over the required change.
Any help will be appreciated !!
CodePudding user response:
Your default log name is based on time, but accuracy is second you must put sleep between logger instance or use non-default names:
dl = DummyLog(log_name="name1")
dl.logger.info("hi")
import time
time.sleep(1)
dl1 = DummyLog(log_name="name2")
dl1.logger.info("hi")
and the result will be
logs
├── name1.log
└── name2.log
I found your code main issue, you use a function call in your default argument:
log_name: str = datetime.now().strftime('%d_%m_%Y__%H_%M_%S'),
by this lang_name
initiate with a string at Class definition time and never changed.
You could use solution like this:
import logging
from datetime import datetime
import sys
import os
class DummyLog:
counter = 0
def __init__(self,
log_name: str = "",
logging_level: str = 'debug',
string_format: str = '%(asctime)s: %(levelname)s: %(message)s',
datetime_format: str = '%m/%d/%Y %I:%M:%S %p',
log_on_folder: bool = True,
log_folder_name: str = 'logs'
):
if log_name:
self.logName = log_name
else:
self.logName = f"{DummyLog.counter}_{datetime.now().strftime('%d_%m_%Y__%H_%M_%S')}"
DummyLog.counter = 1
self.logger = None
self.loggingLevel = logging_level
self.stringFormat = string_format
self.datetimeFormat = datetime_format
if log_on_folder:
if not os.path.exists(log_folder_name):
os.mkdir(log_folder_name)
self.logName = log_folder_name '/' self.logName
self.initiateLogger()
def initiateLogger(self):
""" This function will initiate the logger as a single threaded log"""
self.logger = logging.getLogger(self.logName)
if self.loggingLevel == 'debug':
self.loggingLevel = logging.DEBUG
self.logger.setLevel(self.loggingLevel)
logFormat = logging.Formatter(self.stringFormat, datefmt=self.datetimeFormat)
# Creating and adding the console handler
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(logFormat)
self.logger.addHandler(consoleHandler)
# Creating and adding the file handler
fileHandler = logging.FileHandler(self.logName ".log", mode='w')
fileHandler.setFormatter(logFormat)
self.logger.addHandler(fileHandler)
dl = DummyLog()
dl.logger.info("hi dl")
dl1 = DummyLog()
dl1.logger.info("hi dl1")
dl2 = DummyLog()
dl2.logger.info("hi dl2")
CodePudding user response:
Do not use mutable objects as default parameters. Instead, pass them in runtime or use None as default and set the value.
In your case DateTime is evaluated at function definition time.
Ex:
def __init__(self,
log_name = None,
logging_level: str = 'debug',
string_format: str = '%(asctime)s: %(levelname)s: %(message)s',
datetime_format: str = '%m/%d/%Y %I:%M:%S %p',
log_on_folder: bool = True,
log_folder_name: str = 'logs'
):
if log_name is None:
self.logName = datetime.now().strftime('%d_%m_%Y__%H_%M_%S')
dl = DummyLog()
dl.logger.info("hi")
import time
time.sleep(1)
dl1 = DummyLog()
dl1.logger.info("hi")
OR pass in runtime.
dl = DummyLog(log_name=datetime.now().strftime('%d_%m_%Y__%H_%M_%S'))
dl.logger.info("hi")
import time
time.sleep(1)
dl1 = DummyLog(log_name=datetime.now().strftime('%d_%m_%Y__%H_%M_%S'))
dl1.logger.info("hi")
CodePudding user response:
Thanks to @S4eed3sm for the Answer. I am updating the Answer which creates multiple .log
files and uses datetime.now().strftime('%d_%m_%Y__%H_%M_%S')
to create a log and have a prefix with it
import logging
from datetime import datetime
import sys
import os
class DummyLog:
def __init__(self,
log_name: str = datetime.now().strftime('%d_%m_%Y__%H_%M_%S'),
logging_level: str = 'debug',
string_format: str = '%(asctime)s: %(levelname)s: %(message)s',
datetime_format: str = '%m/%d/%Y %I:%M:%S %p',
log_on_folder: bool = True,
log_folder_name: str = 'logs',
log_prefix: str = None
):
if log_prefix:
self.logName = log_prefix log_name
else:
self.logName = log_name
self.logger = None
self.loggingLevel = logging_level
self.stringFormat = string_format
self.datetimeFormat = datetime_format
if log_on_folder:
if not os.path.exists(log_folder_name):
os.mkdir(log_folder_name)
self.logName = log_folder_name '/' self.logName
self.initiateLogger()
def initiateLogger(self):
""" This function will initiate the logger as a single threaded log"""
self.logger = logging.getLogger(self.logName)
if self.loggingLevel == 'debug':
self.loggingLevel = logging.DEBUG
self.logger.setLevel(self.loggingLevel)
logFormat = logging.Formatter(self.stringFormat, datefmt=self.datetimeFormat)
# Creating and adding the console handler
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(logFormat)
self.logger.addHandler(consoleHandler)
# Creating and adding the file handler
fileHandler = logging.FileHandler(self.logName ".log", mode='w')
fileHandler.setFormatter(logFormat)
self.logger.addHandler(fileHandler)
dl = DummyLog(log_prefix='one_')
dl.logger.info("hi")
dl1 = DummyLog(log_prefix='two_')
dl1.logger.info("hi")
This will create multiple .log
s with prefixes below
logs
├── one_03_01_2022__12_42_02.log
└── two_03_01_2022__12_42_02.log