A variable is excepted as a attribute python logging module - python

Hello Stack Overflow users,
i'm writing a simple code and i got a "AttributeError" exception
log_level = 'INFO' # DEBUG - INFO - WARNING - ERROR - CRITICAL
logging.basicConfig(
format=('%(asctime)s > [%(levelname)s] in %(funcName)s on line '
'%(lineno)d > %(message)s'), level = logging.log_level, \
filename='logs.log', filemode='w', encoding='utf-8')
Sorry for asking a suck stupid question.
Thank you in advance.

Not very clear on your requirement, but the below approach can be a neat solution
def get_logger(cls, logger_name, create_file=False):
# create logger
log = logging.getLogger(logger_name)
log.setLevel(level=logging.INFO)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
if create_file:
# create file handler for logger.
fh = logging.FileHandler('my_log.log')
fh.setLevel(level=logging.DEBUG)
fh.setFormatter(formatter)
# reate console handler for logger.
ch = logging.StreamHandler()
ch.setLevel(level=logging.DEBUG)
ch.setFormatter(formatter)
# add handlers to logger.
if create_file:
log.addHandler(fh)
log.addHandler(ch)
return log

Related

logging is duplicating the log messages

I am trying to learn about logging. My code is logging the information that I want but it's duplicating the message.
The first code block below is at the top of my py file.
import logging
import traceback
# setup the file name
log_file_name = dt.date.today().strftime('%Y_%B_%d')
log_path = "C:/some_path/"
# setup the logging
log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
logger = logging.getLogger(__name__)
logger.setLevel('DEBUG')
file_handler = logging.FileHandler(log_path + log_file_name + '.log')
formatter = logging.Formatter(log_format)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
In my function I'm using the line like below to log some information.
logger.debug('some message')
My py file doesn't import any other modules which have any logging information so I'm a bit confused as to why the messages are being duplicated?

How to use multi logger in Python

I try to use two different loggers to handle different log levels. For example, I want info message store in a file and don't log error message. Error messages of some special functions will email to the user.
I write a simple program to test the logging module.
Code:
import logging
def_logger = logging.getLogger("debuglogger")
def_logger.setLevel(logging.DEBUG)
maillogger = logging.getLogger("mail")
maillogger.setLevel(logging.ERROR)
mailhandler = logging.StreamHandler()
mailhandler.setLevel(logging.ERROR)
mailhandler.setFormatter(logging.Formatter('Error: %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
maillogger.addHandler(mailhandler)
print(def_logger.getEffectiveLevel())
print(maillogger.getEffectiveLevel())
def_logger.info("info 1")
maillogger.info("info 2")
def_logger.error("error 1")
maillogger.error("error 2")
Output:
Output result
I can see the level of them is correct, but both of them act like the level is ERROR.
How can I correctly configure them?
Answer: Base on blues advice, I added a handler and it solved my problem.
Here is the modified code:
import logging
def_logger = logging.getLogger("debuglogger")
def_logger.setLevel(logging.DEBUG)
def_logger.addHandler(logging.StreamHandler()) #added a handler here
maillogger = logging.getLogger("mail")
maillogger.setLevel(logging.ERROR)
mailhandler = logging.StreamHandler()
mailhandler.setLevel(logging.ERROR)
mailhandler.setFormatter(logging.Formatter('Error: %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
maillogger.addHandler(mailhandler)
print(def_logger.getEffectiveLevel())
print(maillogger.getEffectiveLevel())
def_logger.info("info 1")
maillogger.info("info 2")
def_logger.error("error 1")
maillogger.error("error 2")
Neither the def_logger nor any of its parents have a handler attached to it. So what happens is that the logging module falls back to logging.lastResort which by default is a StreamHandler with level Warning. That is the reason why the info message doesn't appear, while the error does. So to solve your problem attach a handler to the def_logger.
Note: In your scenario the only parent both loggers have is the default root handler.
You could add a filter for each logger or handler to process only records of interest
import logging
def filter_info(record):
return True if record.levelno == logging.INFO else False
def filter_error(record):
return True if record.levelno >= logging.ERROR else False
# define debug logger
def_logger = logging.getLogger("debuglogger")
def_logger.setLevel(logging.DEBUG)
def_logger.addFilter(filter_info) # add filter directly to this logger since you didn't define any handler
# define handler for mail logger
mail_handler = logging.StreamHandler()
mail_handler.setLevel(logging.ERROR)
mail_handler.setFormatter(logging.Formatter('Error: %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
mail_handler.addFilter(filter_error) # add filter to handler
mail_logger = logging.getLogger("mail")
mail_logger.setLevel(logging.ERROR)
mail_logger.addHandler(mail_handler)
# test
def_logger.info("info 1")
mail_logger.info("info 2")
def_logger.error("error 1")
mail_logger.error("error 2")
If filter return True, the log record is processed. Otherwise, it is skipped.
Note:
Filter attached to a logger won't be called for log record that is generated by descendant loggers. For example, if you add a filter to logger A, it won't be called for records that are generated by logger A.B nor A.B.C.
Filter attached to a handler is consulted before an event is emitted by that handler.
This means that you just need one logger and add two handlers with different filters attached.
import logging
def filter_info(record):
return True if record.levelno == logging.INFO else False
def filter_error(record):
return True if record.levelno >= logging.ERROR else False
# define your logger
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# define handler for file
file_handler = logging.FileHandler('path_to_log.txt')
file_handler.level = logging.INFO
file_handler.addFilter(filter_info) # add filter to handler
# define handler for mail
mail_handler = logging.StreamHandler()
mail_handler.setLevel(logging.ERROR)
mail_handler.setFormatter(logging.Formatter('Error: %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
mail_handler.addFilter(filter_error) # add filter to handler
logger.addHandler(file_handler)
logger.addHandler(mail_handler)
# test
logger.info("info 1")
logger.info("info 2")
logger.error("error 1")
logger.error("error 2")

own Logger doesn't log Exception, but root logger does

I am trying to log all exceptions within my application. I want to have different handlers, one handler to log all information to a file and only critical problems to my email.
I created a file_handler, which should log everything and email_handler for the critical problems. The handlers work, apart from catching unexpected errors. I tried to log everything with the root logger, which has the same configuration as the file_handler, which works. Why doesn't my file_handler catch unexpected errors?
Here is my code:
# root logger
logging.basicConfig(filename='flask.log', level=logging.WARNING)
# own logger
logger = logging.getLogger('flask')
file_handler = logging.handlers.TimedRotatingFileHandler('flask.log', when='D', interval=1)
email_handler = SMTPHandler(...)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger.setLevel(logging.DEBUG)
file_handler.setLevel(logging.DEBUG)
email_handler.setLevel(logging.WARNING)
file_handler.setFormatter(formatter)
email_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(email_handler)
If I have an error in a function (example Class A doesn't has attribute X), the unexpected problem only gets logged by the root logger.
Workaround:
If I don't give "my" logger a name, I get the root logger. My handlers then take his information and distribute them. It is not ideal, because it should work with "my" logger as well.
Workaround code:
# own logger
logger = logging.getLogger() # no name -> logger = root logger
file_handler = logging.handlers.TimedRotatingFileHandler('flask.log', when='D', interval=1)
email_handler = SMTPHandler(...)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger.setLevel(logging.DEBUG)
file_handler.setLevel(logging.DEBUG)
email_handler.setLevel(logging.WARNING)
file_handler.setFormatter(formatter)
email_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(email_handler)

How to Write Headers in Log File in Python

I have made a log file. Now i want to print a Headers in log file. SO that one can identify what's that column is for.
I have provided the code i have written.
def logger(type_of_message, msg, ticket_no): #This will create records/log in app.log file. And can be used for debuging too.
log_file = str(datetime.utcnow().strftime('%d_%m_%Y')) + '.log'
if(type_of_message == 'INFO' or 'Info'):
logger = logging.LoggerAdapter(logging.getLogger(__name__), {'ticket_no': '%s' % (ticket_no)})
logging.basicConfig(filename = log_file, filemode = 'a', level = logging.INFO, format = '%(ticket_no)s - %(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger.info(msg)
elif(type_of_message == 'ERROR' or 'Error'):
logger = logging.LoggerAdapter(logging.getLogger(__name__), {'ticket_no': '%s'%(ticket_no)})
logging.basicConfig(filename = 'app.log', filemode = 'a', level = logging.ERROR, format = '%(ticket_no)s - %(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger.info(msg)
I want to print it like this:
TICKET NO DATE TIME NAME USER MESSAGE
INC0010265 - 2019-06-25 20:41:54,286 - log - INFO - Mail Send Succesfully
INC0010265 - 2019-06-25 20:41:56,271 - log - INFO - INC0010265 Ticket Update Succesfully
INC0010265 - 2019-06-25 20:41:56,271 - log - INFO - -----Ticket Closed-----
This is not 100% what you're asking for but is closest I can think of.
First of all, you shouldn't call basicConfig more than once for the same program. It actually simply does nothing...
Also, you kinda losing the logging power by defining your own function that checks the message type. It looks funny to call logger.info for an error message. What you should do instead is use Handlers. Check out this code:
import logging
logger = logging.getLogger(__name__)
log_file = str(datetime.utcnow().strftime('%d_%m_%Y')) + '.log'
error_handler = logging.FileHandler("app.log")
error_handler.setLevel(logging.ERROR)
info_handler = logging.FileHandler(log_file)
info_handler.setLevel(logging.INFO)
logger.setLevel(logging.INFO)
logger.addHandler(info_handler)
logger.addHandler(error_handler)
header_formatter = logging.Fomatter('%(message)s')
default_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
error_handler.setFormatter(header_formatter)
info_handler.setFormatter(header_formatter)
logger.error("DATE\t\tTIME\t\tNAME\t\tUSER\t\tTICKET NO\tMESSAGE")
error_handler.setFormatter(default_formatter)
info_handler.setFormatter(default_formatter )
A few explanations:
We are using two handlers: error_handler and info_handler to direct different types of messages to different files. NOTE that in this way error messages will be also in the info file.
We set the logger's level to the minimal between them (in this case INFO) and add to it our handlers.
Then we use special formatters to the header and regular messages. We first assign to both handlers the header formatter. We then print the header (using logger.error so it will go to both logs). And then set the handlers with the regular formatter.
All messages logged from this point on will be in the regular format.
2nd NOTE: I couldn't find a way to add a field to the fomat as what you tried to acheive for ticket_no. As you can see I moved the column to be before the messgae so simply add the ticke_no in the start of your message. What you can do is for example:
def log_msg(logger, type_of_message, msg, ticket_no):
msg = "{}\t{}".format(ticket_no, msg)
if(type_of_message == 'INFO' or 'Info'):
logger.info(msg)
elif(type_of_message == 'ERROR' or 'Error'):
logger.error(msg)

Enable to log the debug statements

Below are 2 different modules: driver module and employee module. I am
trying the log the debug statements in two different files but write now the
log file is getting created with no debug statements in it.
I tried all the way.
Driver file
import logging
logger = logging.getLogger(__name__)
formatter = logging.Formatter("%(asctime)s : %(levelname)s : %(name)s : %
(message)s")
file_handler = logging.FileHandler('driver.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
#logging.basicConfig(filename="Employee.log", level=logging.DEBUG,
format="%(asctime)s : %(levelname)s : %(name)s : %(message)s")
from Employee import Employee
logger.debug("Before creation of object")
Emp1= Employee("Rahul",1,100000)
logger.debug("After creation of object")
Emp1.display()
#Employee Module
import logging
logger = logging.getLogger(__name__)
formatter = logging.Formatter("%(asctime)s : %(levelname)s : %(name)s : %
(message)s")
file_handler = logging.FileHandler("Employee.log")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
#logging.basicConfig(filename="Employee.log", level=logging.DEBUG,
format="%(asctime)s : %(levelname)s : %(name)s : %(message)s")
class Employee():
def __init__(self,name,id,salary):
self.salary = salary
self.name=name
self.id =id
def increment(self, per):
self.salary=self.salary*((100+per)/100)
def decrement(self, per):
self.salary=self.salary*((100-per)/100)
def display(self):
logger.debug("Name is {}".format(self.name))
logger.debug("ID is {}".format(self.id))
logger.debug("Sal is {}".format(self.salary))
You need to set the level on the logger instance as well. The handlers and the logger each have a level. A logger can have multiple handlers assigned to it, each logging at a different level.
logger.setLevel(logging.DEBUG)
Edit: https://docs.python.org/3/library/logging.html#logging.Logger.setLevel

Categories

Resources