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
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
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...')
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.
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')
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)