print statements are not coming on console with logging module - python

I am using below logging code in unittest module framework
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(output_dir, "w")
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
Problem is that when I am having print statements in the code, these are not getting printed anywhere. Not on the console and not in the output file (though I understand why these are not getting printed in file).
Can anybody tell me the reason and solution to print print statements on the console
I am using python 2.7

You aren't setting StreamHandler anywhere, modified your example below.
import logging
output_dir = "/tmp/somefile"
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(output_dir, "w")
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
# HERE
ch = logging.StreamHandler()
logger.addHandler(ch)
logger.info("test")
logger.info("test")
logger.info("test")
logger.info("test")
This gives me both output on console as well as in file.
EDIT:
Not the best idea, agree, but taken straight from documentation
import logging
import unittest
logger = None
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
logger.info(self)
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
logger.info(self)
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
logger.info(self)
def setup_log():
global logger
output_dir = "/tmp/somefile"
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(output_dir, "w")
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
ch = logging.StreamHandler()
logger.addHandler(ch)
logger.info("Logger ready")
if __name__ == '__main__':
setup_log()
unittest.main()
It works, so probably you have some other problem in your code, if you update with more elaborate version, perhaps we can help.

Related

How to disable python logging stdout and have it just inside the log file

I want to disable my script to print the INFO, DEBUG, WARNING or ERROR from logging commands and just have this inside the .log or .err. Here is the configuration I have:
def log(routine_name):
""" Logging configuration """
logger = logging.getLogger(_name_)
logger.setLevel(logging.INFO)
logging.StreamHandler(stream=None)
formatter = logging.Formatter("%(asctime)s:%(levelname)s:%(name)s:%(message)s")
file_handler = logging.FileHandler(routine_name)
file_handler.setFormatter(formatter)
error_handler = logging.FileHandler(routine_name.replace("log", "err"))
error_handler.setFormatter(formatter)
error_handler.setLevel(logging.ERROR)
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.addHandler(error_handler)
return logger
I have tried to set logger.propagate = False from this post but didn't work, it still printing everything.
Thanks
For me this did work with module.submodule issuing the logging commands
logger = logging.getLogger("module.submodule")
fh = logging.FileHandler("logfile")
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
logger.disabled = True

Python needs to log each script into its own log

I have scripts parent.py and child.py (many childs) and I need to have logs for each, so any logging within parent.py should be in parent.log and child.py should be in child.log
I have the below in each script but I get empty logs... why??
#main.py
import child
handler = logging.FileHandler('logs/main.log')
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s [%(filename)s:%(lineno)s - %
(funcName)10s()] %(levelname)s: %(message)s")
handler.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger.addHandler(handler)
child.child_func()
logger.info('testing parent...')
#child.py
handler = logging.FileHandler('logs/child.log')
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s [%(filename)s:%(lineno)s - %
(funcName)10s()] %(levelname)s: %(message)s")
handler.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger.addHandler(handler)
def child_func():
logger.info('testing child...')
What I need to have is
#parent.log
{format} testing parent...
#child.log
{format} testing child...
The folks above are right about the default level on the loggers. Also, instead of spreading your configuration around everywhere, I find it more manageable to consolidate logging configuration to be early on in the application. See the example below.
Note: I don't expect this to be selected as an answer. I just wanted to point out what I believe is a better way of organizing the code.
main.py
import logging
import child
logger = logging.getLogger(__name__)
def setup_logging():
main_handler = logging.FileHandler('logs/main.log')
child_handler = logging.FileHandler('logs/child.log')
# Note that you can re-use the same formatter for the handlers.
formatter = logging.Formatter("%(asctime)s [%(filename)s:%(lineno)s - %(funcName)10s()] %(levelname)s: %(message)s")
main_handler.setFormatter(formatter)
child_handler.setFormatter(formatter)
# By default, loggers inherit the level from their parent, so we only need
# to set the level on the root logger if you want to have only one knob to
# control the level.
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
main_logger = logging.getLogger(__name__)
child_logger = logging.getLogger('child')
child_logger.propagate = False
main_logger.addHandler(main_handler)
child_logger.addHandler(child_handler)
def main():
setup_logging()
child.child_func()
logger.info('testing parent...')
if __name__ == '__main__':
main()
child.py
import logging
logger = logging.getLogger(__name__)
def child_func():
logger.info('testing child...')
Setting up a root logger and a child logger (no main)
Here's an example of setting up the root logger to log to logs/main.log, and the child logger to go to logs/child.log
def setup_logging():
root_handler = logging.FileHandler('logs/main.log')
child_handler = logging.FileHandler('logs/child.log')
# Note that you can re-use the same formatter for the handlers.
formatter = logging.Formatter("%(asctime)s [%(filename)s:%(lineno)s - %(funcName)10s()] %(levelname)s: %(message)s")
root_handler.setFormatter(formatter)
child_handler.setFormatter(formatter)
# By default, loggers inherit the level from their parent, so we only need
# to set the level on the root logger if you want to have only one knob to
# control the level.
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(root_handler)
child_logger = logging.getLogger('child')
child_logger.propagate = False
child_logger.addHandler(child_handler)
You can set severity-level on both handlers and loggers - I believe the logger is set to logging.WARNING by default, so you would only get warning-logs using your code.
You can read more in this thread: What is the point of setLevel in a python logging handler?
import logging
import child
handler = logging.FileHandler('logs/main.log')
formatter = logging.Formatter("%(asctime)s [%(filename)s:%(lineno)s - %(funcName)10s()] %(levelname)s: %(message)s")
handler.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG) # <-- changed
child.child_func()
logger.info('testing parent...')
logger.warning('testing parent...')
logger.debug('testing parent...')
#child.py
import logging
handler = logging.FileHandler('logs/child.log')
formatter = logging.Formatter("%(asctime)s [%(filename)s:%(lineno)s - %(funcName)10s()] %(levelname)s: %(message)s")
handler.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG) # <-- changed
def child_func():
logger.info('testing child...')
logger.warning('testing child...')
logger.debug('testing child...')

python: difference between logging.Logger and logging.getLogger

Yes, I see python doc says: "Loggers are never instantiated directly, but always through the module-level function logging.getLogger(name)", but I have an issue to debug and want to know the root cause.
here is the example:
#!/usr/bin/python
import logging
logger = logging.getLogger("test")
format = "%(asctime)s [%(levelname)-8s] %(message)s"
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(format, datefmt="%Y-%m-%d %H:%M:%S"))
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.info("test")
Using logging.getLogger("test") here, log message will not be printed.
If I change logging.getLogger("test") to logging.Logger("test"), the log message will be printed.
#!/usr/bin/python
import logging
logger = logging.Logger("test")
format = "%(asctime)s [%(levelname)-8s] %(message)s"
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(format, datefmt="%Y-%m-%d %H:%M:%S"))
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.info("test")
Or we can using logging.getLogger("test") and set logger level to logging.DEBUG.
#!/usr/bin/python
import logging
logger = logging.getLogger("test")
format = "%(asctime)s [%(levelname)-8s] %(message)s"
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(format, datefmt="%Y-%m-%d %H:%M:%S"))
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.info("test")
The method .getLogger("test") is looking for any existing logger configurations for the name "test" while the .Logger("test") is creating a default logger with the name "test" and sets the default log level to 0. If the getLogger method doesn't find a logger class by that name then it will create a basic logger that will have an effective level of 30 (https://docs.python.org/3/library/logging.html#logging-levels) which will ignore your DEBUG message. You can check via logger.getEffectiveLevel() to notice the difference.
Ideally you would create loggers and set them based on the proper naming/configurations instead of accepting the default configuration.

Logging to two files with different settings

I am already using a basic logging config where all messages across all modules are stored in a single file. However, I need a more complex solution now:
Two files: the first remains the same.
The second file should have some custom format.
I have been reading the docs for the module, bu they are very complex for me at the moment. Loggers, handlers...
So, in short:
How to log to two files in Python 3, ie:
import logging
# ...
logging.file1.info('Write this to file 1')
logging.file2.info('Write this to file 2')
You can do something like this:
import logging
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
def setup_logger(name, log_file, level=logging.INFO):
"""To setup as many loggers as you want"""
handler = logging.FileHandler(log_file)
handler.setFormatter(formatter)
logger = logging.getLogger(name)
logger.setLevel(level)
logger.addHandler(handler)
return logger
# first file logger
logger = setup_logger('first_logger', 'first_logfile.log')
logger.info('This is just info message')
# second file logger
super_logger = setup_logger('second_logger', 'second_logfile.log')
super_logger.error('This is an error message')
def another_method():
# using logger defined above also works here
logger.info('Inside method')
def setup_logger(logger_name, log_file, level=logging.INFO):
l = logging.getLogger(logger_name)
formatter = logging.Formatter('%(message)s')
fileHandler = logging.FileHandler(log_file, mode='w')
fileHandler.setFormatter(formatter)
streamHandler = logging.StreamHandler()
streamHandler.setFormatter(formatter)
l.setLevel(level)
l.addHandler(fileHandler)
l.addHandler(streamHandler)
setup_logger('log1', txtName+"txt")
setup_logger('log2', txtName+"small.txt")
logger_1 = logging.getLogger('log1')
logger_2 = logging.getLogger('log2')
logger_1.info('111messasage 1')
logger_2.info('222ersaror foo')

Restart logging to a new file (Python)

I'm using the following code to initialize logging in my application:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# log to a file
directory = '/reserved/DYPE/logfiles'
now = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(directory, 'dype_%s.log' % now)
file_handler = logging.FileHandler(filename)
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(filename)s, %(lineno)d, %(funcName)s: %(message)s")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# log to the console
console_handler = logging.StreamHandler()
level = logging.INFO
console_handler.setLevel(level)
logger.addHandler(console_handler)
logging.debug('logging initialized')
How can I close the current logging file and restart logging to a new file?
Note: I don't want to use RotatingFileHandler, because I want full control over all the filenames.
You can manually re-assign the handler if you want using the removeHandler and addHandler OR, you can access logger.handlers[index_of_handler_here].stream and replace the stream manually, but I'd recommend the former over the latter.
logger.handlers[0].stream.close()
logger.removeHandler(logger.handlers[0])
file_handler = logging.FileHandler(filename)
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(filename)s, %(lineno)d, %(funcName)s: %(message)s")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
Here is what I do:
def initLogging(filename):
global logger
if logger == None:
logger = logging.getLogger()
else: # wish there was a logger.close()
for handler in logger.handlers[:]: # make a copy of the list
logger.removeHandler(handler)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(fmt='%(asctime)s: %(message)s', datefmt='%I:%M:%S')
fh = logging.FileHandler(filename)
fh.setFormatter(formatter)
logger.addHandler(fh)
sh = logging.StreamHandler(sys.stdout)
sh.setFormatter(formatter)
logger.addHandler(sh)

Categories