How to Customize the message format for Python logging? - python-3.x

Im in the process of setting up a logger for my programm
custom_logger = logging.getLogger(__name__)
custom_logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s;%(message)s;%(filename)s;%(lineno)d',"%Y-%m-%d %H:%M:%S")
file_handler = logging.FileHandler('beispiel.log')
file_handler.setFormatter(formatter)
custom_logger.addHandler(file_handler)
I want to logg this part custom_logger.info(z1serial.isOpen())
it adds a TRUE to the log file
2020-03-03 13:47:38;True;test.py;55
how can I insert a specific message like `device connected; True, so it apears in the log file ?

to insert a argument to the message it needs to be in format string like this
custom_logger.debug('device connected: %s',z1serial.isOpen())
nothing fancy

Related

How to stop python log printing in console

I am using the following code. Still my logs are being printed both in console and log file. Can anyone please help me to identify how to stop printing log in the console
logger = logging.getLogger('MyLog')
logger.handlers = []
hdlr = logging.handlers.RotatingFileHandler(LOG_FILE_PATH, maxBytes = ConfConst.MAX_LOG_FILE_SIZE , backupCount= ConfConst.MAX_LOG_FILE_BACKUP_COUNT)
formatter = logging.Formatter('[%(asctime)s] p%(process)s {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s','%m-%d %H:%M:%S')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logging.StreamHandler(stream=None)
logger.setLevel(logging.INFO)
Use this it may help you
logger = logging.getLogger()
logger.disabled = True
... whatever you want ...
logger.disabled = False

my first custom logging handler not working

I am trying to write custom handler for logging that would send logs to netcat
I can see on the receiving end that the connection is established and then closes, however, no messages are received and i can see no errors.
here is the code i am running
import socket
import time
import logging
hostname = '127.0.0.1'
port = '1234'
message = 'hello world!\n'
class Nc_handler(logging.Handler):
def __init__(self, hostname, port):
logging.Handler.__init__(self)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((hostname, int(port)))
def emit(self, content):
log_entry = self.format(content)
print("Checking if emit is run")
self.socket.send(log_entry.encode())
logger = logging.getLogger(__name__)
# set format
nc_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
# create nc handler
nc_handler = Nc_handler(hostname, port)
# set handler's level
nc_handler.setLevel(logging.INFO)
# set handler's format
nc_handler.setFormatter(nc_format)
logger.addHandler(nc_handler)
logger.info(message)
If i use nc_handler.emit('Hello') it throws an error:
File "handler.py", line 35, in <module>
nc_handler.emit(message)
File "handler.py", line 17, in emit
log_entry = self.format(content)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/logging/__init__.py", line 869, in format
return fmt.format(record)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/logging/__init__.py", line 608, in format
record.message = record.getMessage()
AttributeError: 'str' object has no attribute 'getMessage'
So i suspect i don't use Formatter correctly but I can't figure out what exactly I am doing wrong.
I would really appreciate any help or advice.
Method emit has a wrong signature: its argument must be a LogRecord object. Not a string.
That is because format method needs a LogRecord object.
That is the cause of the AttributeError exception.
I see also a confusion I don't understand: why using message as argument for logging.info?
message is an attribute of the LogRecord object too and is taken from what you logged explicitly.
Use a hard-coded string:
logging.info("Hello")
Or use a different variable:
myvar = "Hello"
logging.info(myvar)
Does it help?

How to set a logging level per handler and per module using python's logging module

I'd like to set different logging levels per handler and logger in python. I'd like debug level logs for all loggers to be sent to their filehandlers, but be able to individually select the log level for each logger for what's printed to the console.
import logging
loggerA = logging.getLogger('a')
fhA = logging.FileHandler(filename='a.log', mode='w')
fhA.setLevel(logging.DEBUG)
loggerA.addHandler(fhA)
loggerB = logging.getLogger('b')
fhB = logging.FileHandler(filename='b.log', mode='w')
fhB.setLevel(logging.DEBUG)
loggerB.addHandler(fhB)
logging.basicConfig(level=logging.INFO)
logging.getLogger('a').setLevel(logging.INFO)
logging.getLogger('b').setLevel(logging.WARN)
loggerA.info("TEST a")
loggerB.info("TEST b")
I'd expect all logs to be sent to the files, but only show WARNING and above from 'b' in the console, and INFO and above from 'a' in the console. With the above code, 'b' doesn't have any logs in the file.

Why don't my lower level logs write to the file, but the error and above do?

I created a small function to setup logging, with a filehandler for 'everything', and smtphandler for error and above. Error logs write to the log file and send correctly to email, but debug, info, notset don't, even though setlevel is set to 0 for filehandler. Why's that? Code below
#logsetup.py
import logging
import logging.handlers
def _setup_logger(name, log_file):
"""Function to setup logger"""
logger = logging.getLogger(name)
#Create Formatters
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
mail_formatter = logging.Formatter('%(name)s - %(message)s')
#Create handler, set formatting, set log level
file_handler_obj = logging.FileHandler(log_file)
file_handler_obj.setFormatter(file_formatter)
file_handler_obj.setLevel(0)
#Create handler, set formatting, set log level
smtp_handler_obj = logging.handlers.SMTPHandler(mailhost=('smtp.gmail.com', 587),
fromaddr='mymail#example.com',
toaddrs='mymail#example.com',
subject='Error in Script',
credentials=('mymail#example.com', 'pwexample'), #username, password
secure=())
smtp_handler_obj.setFormatter(mail_formatter)
smtp_handler_obj.setLevel(logging.ERROR)
# add the handlers to logger
logger.addHandler(smtp_handler_obj)
logger.addHandler(file_handler_obj)
return logger
#mytest.py
import time
import logsetup
if __name__ == '__main__':
TEST_SETTINGS = config_funcs._get_config('TEST_SETTINGS')
logtime = time.strftime('%Y%m%d') # -%H%M%S")
log = logsetup._setup_logger('TEST', TEST_SETTINGS['logging_dir'] + 'Py_Log_%s.log' % logtime)
log.error('Writes to log file and sends email')
log.debug('Supposed to write to log file, does nothing.')
Apparently, logging needs it's own logging level aside from the handlers. Setting logger.setLevel(logging.DEBUG) right before returning logger causes it to work correctly. Documentation says
When a logger is created, the level is set to NOTSET (which causes all
messages to be processed when the logger is the root logger, or
delegation to the parent when the logger is a non-root logger). Note
that the root logger is created with level WARNING.
Which means that if the handlers are lower level than the root logger (which ERROR is not, but DEBUG is) then the handlers which I guess is a child because I'm getting a named logger? Not quite sure on the why of it, but that does 'fix' it, in case anyone comes to this later.

Python logging printing double to console

It seems that on a couple machines I'm getting double output like this:
INFO LED NOTIFICATION STARTED
INFO:output_logger:LED NOTIFICATION STARTED
This is the function I'm using:
def setup_logger(name, log_file, level=logging.INFO, ContentFormat='%(asctime)s %(levelname)s %(message)s', DateTimeFormat="%Y-%m-%d %H:%M:%S", CreateConsoleLogger=False):
"""Function setup as many loggers as you want"""
logger = logging.getLogger(name)
logger.setLevel(level)
if CreateConsoleLogger:
# create console handler
handler = logging.StreamHandler()
handler.setLevel(level)
formatter = logging.Formatter("%(levelname)s %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
# create a file handler
handler = RotatingFileHandler(log_file, maxBytes=2000000, backupCount=5)
handler.setLevel(level)
formatter = logging.Formatter(ContentFormat, DateTimeFormat)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
This is how I'm creating the logger:
output_logger = setup_logger('output_logger', 'log/autofy.log', level=logging.DEBUG, CreateConsoleLogger=True)
And this is how I call it:
output_logger.info("LED NOTIFICATION STARTED")
On a most of computers I just see the same message printed to the console that's saved to the file as expected ("INFO LED NOTIFICATION STARTED"), but on other computers it's doing this weird double output thing. My code is exactly the same from one computer to another, so any ideas what could be causing this on some computers and not others?
EDIT
I'm writing the script using notepad++ and running it in a terminal window on an Ubuntu 16.04 machine. I'm using python3.
Try adding this to your code:
logging._get_logger().propagate = False

Resources