Simply_me
Simply_me

Reputation: 2970

No Log File Created

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

Answers (1)

zwer
zwer

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

Related Questions