Reputation: 2970
I've been learning about logging, and got help here earlier on setting up a logger w/external config file.
I've setup based on the example, however the messages only seen on the console and not in a long file (not created.
Can you please see what I'm doing wrong?
utilityLogger:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
My app
'''
# ~~~~~ LOGGING SETUP ~~~~~ #
# set up the first logger for the app
import os
import testLogging as vlog
# path to the current script's dir
scriptdir = os.path.dirname(os.path.realpath(__file__))
LOG_CONFIG = '../config/logging.conf'
print scriptdir
def logpath():
'''
Return the path to the main log file; needed by the logging.yml
use this for dynamic output log file paths & names
'''
global scriptdir
return (vlog.logpath(scriptdir = scriptdir, logfile = 'log.txt'))
logger = vlog.log_setup(config_file=LOG_CONFIG, logger_name="app")
logger.debug("App is starting...")
testLogging:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Functions to set up the app logger
'''
import logging
import logging.config
import os
LOG_CONFIG = '../config/logging.conf'
def logpath(scriptdir, logfile):
'''
Return the path to the main log file; needed by the logging.yml
use this for dynamic output log file paths & names
'''
log_file = os.path.join(scriptdir, logfile)
print log_file
print scriptdir
print logfile
return(logging.FileHandler(log_file))
def log_setup(config_file, logger_name):
'''
Set up the logger for the script
config = path to YAML config file
'''
# Config file relative to this file
logging.config.fileConfig(config_file)
return(logging.getLogger(logger_name))
logging.conf file:
[loggers]
keys=root
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
qualname=app
[logger_app]
level=DEBUG
handlers=consoleHandler
qualname=app
propagate=true
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=fileFormatter
args=('%(logfilename)s',)
[main]
()=__main__.logpath
level=DEBUG
formatter=simpleFormatter
[formatter_fileFormatter]
format=%(asctime)s (%(name)s:%(funcName)s:%(lineno)d:%(levelname)s) %
(message)s # %(module)s:
datefmt="%Y-%m-%d %H:%M:%S"
[formatter_simpleFormatter]
format=%(asctime)s (%(name)s:%(funcName)s:%(lineno)d:%(levelname)s) %(message)s # %(module)s:
datefmt="%Y-%m-%d %H:%M:%S"
Update, the question has already been marked as answered and I appreciate @zwer help!
Last objective, to understand, is there more pythonic way to instantiate a logger to Class (but I want to be able to log in main as well). With the marked answer I've put together the following, but I'm not sure it's the most elegant solution for both main and classes logging.
class TestLog(object):
def __init__(self, logger):
self.logger = logger
self.__sub_test = 0
def add_test(self):
self.logger.debug('addition')
a = 1 + 1
self.logger.debug('result {}'.format(a, 1))
def sub_test(self):
self.logger.debug('subtraction')
b = 5 -2
self.logger.debug('result {}'.format(b, 1))
def main():
logger = vlog.log_setup(config_file=LOG_CONFIG, logger_name="app",
log_file=LOG_PATH)
logger.debug("App is starting...")
test1 = TestLog(logger)
print test1.add_test()
print test1.sub_test()
if __name__ == "__main__":
sys.exit(main())
Upvotes: 0
Views: 962
Reputation: 25779
Alright, let's pack it as an answer to avoid comment constraints.
The main issue with your config is that you're not initializing your fileHandler at all. If you want to use it, make sure you add it to the [handlers]
section, e.g.:
[handlers] keys=fileHandler
As for your other error, since in your [handler_fileHandler]
you define a dynamic argument logfilename
for the name of the file so you need to provide it when you're loading your logging config in Python, e.g.:
logging.config.fileConfig(config_file, defaults={"logfilename": "your_log_filename.log"})
That should do the trick.
UPDATE - As long as you provide a proper file path, the stated should work, but you still need to modify your config a little bit more to enable the file logger in all your loggers. So change your config to:
[loggers] keys=root [handlers] keys=consoleHandler,fileHandler [formatters] keys=simpleFormatter,fileFormatter [logger_root] level=DEBUG handlers=consoleHandler,fileHandler qualname=app [logger_app] level=DEBUG handlers=consoleHandler,fileHandler qualname=app propagate=true [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=simpleFormatter args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=DEBUG formatter=fileFormatter args=('%(logfilename)s',) [main] ()=__main__.logpath level=DEBUG formatter=simpleFormatter [formatter_fileFormatter] format=%(asctime)s (%(name)s:%(funcName)s:%(lineno)d:%(levelname)s) %(message)s # %(module)s: datefmt="%Y-%m-%d %H:%M:%S" [formatter_simpleFormatter] format=%(asctime)s (%(name)s:%(funcName)s:%(lineno)d:%(levelname)s) %(message)s # %(module)s: datefmt="%Y-%m-%d %H:%M:%S"
Also, to make it more flexible, change your testLogging.log_setup()
to something like:
def log_setup(config_file, logger_name, log_file):
# Config file relative to this file
logging.config.fileConfig(config_file, defaults={"logfilename": log_file})
return logging.getLogger(logger_name)
And finally, when you're setting it up just invoke it as:
LOG_CONFIG = '../config/logging.conf'
LOG_PATH = r"C:\PycharmProjects\scrap\test.log" # make sure it exists and is accessible!
logger = vlog.log_setup(config_file=LOG_CONFIG, logger_name="app", log_file=LOG_PATH)
logger.debug("App is starting...")
Adjusted for your local paths it should work as expected. I just tested it on my side and it's giving a proper result.
Upvotes: 2