FAQ
Here is an example straight out of the help, and for some reason, it
is not working. I get the error messages in the log, but I do not get
the info messages in the console.

import datetime, logging

def main():
timestamp = datetime.datetime.now().strftime("%Y%m%d-%I%M%S")
#set up logging
logfile = os.path.join('db_backup_' + timestamp + '.log')
logging.basicConfig(filename=logfile,
level=logging.WARN,
format="%(asctime)s - %(levelname)s - %
(message)s",
datefmt="%H:%M:%S")
# define a Handler which writes INFO messages or higher to the
sys.stderr
console = logging.StreamHandler()
console.setLevel(logging.INFO)
# set a format which is simpler for console use
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %
(message)s')
# tell the handler to use this format
console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger('').addHandler(console)
conlog = logging.getLogger('console')
#logging is now configured
conlog.info('In Main')
logging.error('An error occured.')

Search Discussions

  • Kev Dwyer at Oct 18, 2010 at 9:25 pm

    On Mon, 18 Oct 2010 11:52:36 -0700, robinsiebler at gmail.com wrote:

    Here is an example straight out of the help, and for some reason, it is
    not working. I get the error messages in the log, but I do not get the
    info messages in the console.
    Hello,

    I don't see this code in the help; nevertheless, your code will work
    if you set the logging level in the logging.basicConfig() call to
    logging.INFO or lower.

    I suggest that you start by trying to output to just one handler,
    and play around with that before trying to configure multiple
    handlers.

    Sorry not to be more helpful, but it's late here.

    Cheers (apologetically),

    Kev
  • Robinsiebler at Oct 18, 2010 at 9:45 pm
    If I set logging.basicConfig() call to logging.INFO, then I see info
    messages in the logfile. I only want to see error messages in the
    logfile.
  • Vinay Sajip at Oct 18, 2010 at 11:45 pm

    On Oct 18, 10:45?pm, "robinsieb... at gmail.com" wrote:
    If I setlogging.basicConfig() call tologging.INFO, then I see info
    messages in the logfile. I only want to see error messages in the
    logfile.
    What you need to do is,

    1. Set the root logger's level to INFO. That's because you want at
    least INFO messages to go somewhere.
    2. Don't use basicConfig(), but instead create a console handler and a
    file handler explicitly.
    3. Set the file handler's level to ERROR, so only ERROR messages and
    higher go to the file.
    4. Set the console handler's level to INFO, so INFO messages and
    higher go to console.

    With this setup, the console will show INFO, WARNING, ERROR, CRITICAL
    messages. The log file will show ERROR, CRITICAL messages.

    If you need anything more involved (for example, you ONLY want INFO
    messages to be shown on the console) you'll need to set up a suitable
    Filter and add it to the console handler to filter out messages you
    don't want. See the logging docs for more info on Filters.

    Regards,

    Vinay Sajip
  • Chris Torek at Oct 19, 2010 at 9:59 am

    On Oct 18, 10:45?pm, "robinsieb... at gmail.com" wrote:
    If I setlogging.basicConfig() call tologging.INFO, then I see info
    messages in the logfile. I only want to see error messages in the
    logfile.
    I am not sure how good the documentation is (having not gone back
    to look at it) but I had the same problem when I first started using
    the logging module for a server. Vinay Sajip's recipe below is
    correct, the only thing missing is "why it is correct":

    In article <0945c1e3-f575-4940-8f2c-0374308a366e at j18g2000yqd.googlegroups.com>
    Vinay Sajip wrote:
    What you need to do is,

    1. Set the root logger's level to INFO. That's because you want at
    least INFO messages to go somewhere.
    2. Don't use basicConfig(), but instead create a console handler and a
    file handler explicitly.
    3. Set the file handler's level to ERROR, so only ERROR messages and
    higher go to the file.
    4. Set the console handler's level to INFO, so INFO messages and
    higher go to console.
    The reason for step 2 (avoid logging.basicConfig()) is that
    basicConfig() creates a handler that goes to sys.stderr. There is
    no way to adjust that handler. (Well, it is on a list of handlers
    that you could peek into, but that seems ... unwise.)
    If you need anything more involved (for example, you ONLY want INFO
    messages to be shown on the console) you'll need to set up a suitable
    Filter and add it to the console handler to filter out messages you
    don't want. See the logging docs for more info on Filters.
    Here's a moderately complex example that is full of some bad coding
    practices :-) but shows how to do some fancy things. I snipped it
    out of a real program, so there are parts that probably look kind
    of whacky but have some real purpose; other parts that look whacky
    are because I wrote a lot of this while in early "learning Python"
    stages.

    import logging.handlers

    logger = None

    [Next is a hack I was experimenting with to sort-of-hide
    some globals ... much irrelevant stuff has been snipped out,
    so everything you see in "g" here is purely for logging, and
    it would make more sense to have a class for logging control
    to retain this stuff. As I said, early code. :-) ]

    class g: pass

    # syslog adds its own time and level stamp.
    g.syslog_format = (
    'nodemgr: %(threadName)s %(message)s'
    ' - %(filename)s/%(funcName)s:%(lineno)d'
    )
    g.stderr_format = '%(levelname)-8s (%(threadName)s) %(message)s'
    g.log_format = (
    '%(asctime)s: ' + g.stderr_format +
    ' - %(filename)s/%(funcName)s:%(lineno)d'
    )

    # these are actually "log handlers"
    g.file_logger = None
    g.stderr_logger = None
    g.syslog_logger = None

    # Set up initial logger.
    #
    # Although it is labeled "temporary", it persists: it is
    # just its configuration that is "temporary", until we read
    # the config file.
    def init_temporary_logger():
    global logger

    # Get "master" logger with stderr "slave". Note that we
    # set the master level no higher than DEBUG, otherwise the slaves
    # never see DEBUG-level entries.
    #
    # Can't use basicConfig here as it creates a sys.stderr
    # StreamHandler that we can't adjust later. Just omit the call:
    # logging.basicConfig(level = logging.DEBUG, format = ...)
    # which leaves logging.root unset, which is OK.
    nl = logging.getLogger('nodemgr')
    nl.setLevel(logging.DEBUG)
    stream = logging.StreamHandler(sys.stderr)
    stream.setFormatter(logging.Formatter(g.stderr_format))
    stream.setLevel(logging.INFO) # until later
    nl.addHandler(stream)
    g.stderr_logger = stream
    logger = nl

    # Get a syslog "address" given a string.
    def get_syslog_addr(syslog_to):
    # Syslog takes either a host name and optional port, or a path
    # name to a file. We choose here based on a regexp match.
    m = re.compile('([^/:]+)(:([0-9]+))?$').match(syslog_to)
    if m:
    (host, _, port) = m.groups()
    if port is not None:
    try:
    port = int(port)
    except ValueError:
    port = 0
    if port < 1 or port > 65535:
    logger.error('syslog-to=%s: bad port number', syslog_to)
    port = 0
    addr = (host, port or logging.handlers.SYSLOG_UDP_PORT)
    else:
    addr = syslog_to
    return addr

    # Update logger based on configuration.
    def update_logger(conf):
    global logger

    # Helper function for swapping out syslog and file loggers.
    def swapout(old, new):
    if old != new and old is not None:
    logger.removeHandler(old)
    if new is not None:
    logger.addHandler(new)
    return new

    # Helper function: is given fd already open to given file name?
    # (Note that this gives you a slightly stale answer, in that the
    # name to underlying file mapping can change in the presence of
    # a rename. Do not use this for security-issue operations.)
    def fd_is_open_to(fileno, filename):
    try:
    s2 = os.stat(filename)
    except OSError:
    return False
    s1 = os.fstat(fileno)
    return s1.st_dev == s2.st_dev and s1.st_ino == s2.st_ino

    errs = False

    # Configure our logs as directed.
    logconf = conf['logging']

    # First, adjust stderr output level. We deliberately do
    # this before changing other log handers, so that new debug
    # messages printed here can be seen. (Maybe should do "raise"
    # now and "lower" later, but does not seem worth the effort.)
    level = logging.getLevelName(logconf['stderr-level'].upper())
    g.stderr_logger.setLevel(level)

    # Gripe about old unsupported config, if needed.
    if conf['USE-FAST-LOGGER']:
    logger.error('FAST logger no longer supported')
    errs = True

    # Now set up syslog logger, if any.
    syslog_to = logconf['syslog-to']
    if syslog_to:
    # Might be nice to remember previous syslog-to (if any)
    # and not create and delete handler if unchanged. (But
    # see comments elsewhere within this function.)
    addr = get_syslog_addr(syslog_to)
    logger.debug('syslog to: %s' % str(addr))
    try:
    sh = logging.handlers.SysLogHandler(addr,
    logging.handlers.SysLogHandler.LOG_DAEMON)
    sh.setFormatter(logging.Formatter(g.syslog_format))
    except IOError, e:
    logger.error('syslog-to: %s', e)
    errs = True
    sh = g.syslog_logger
    level = logging.getLevelName(logconf['syslog-level'].upper())
    if sh:
    sh.setLevel(level)
    else:
    logger.debug('syslog logging suppressed')
    sh = None

    # And file logger, if any.
    filepath = logconf['file']
    if filepath:
    if not os.path.isabs(filepath):
    newpath = os.path.join(conf['NODEMGR-BASE-PATH'], filepath)
    logger.warning('logging file=%s: relative path converted to %s',
    filepath, newpath)
    filepath = newpath
    logger.debug('filelog to: %s' % str(filepath))
    mode = logconf['mode']
    maxsize = logconf['max-size']
    try:
    maxsize = utils.string_to_bytes(maxsize)
    except ValueError:
    logger.error('logging max-size=%s: not a valid size', maxsize)
    maxsize = 1 * 1024 * 1024 # 1 MB
    backup_count = logconf['backup-count']
    level = logging.getLevelName(logconf['level'].upper())
    # If mode is 'w' and maxsize==0, this will open an existing
    # file for writing, truncating it. If the existing file is
    # our own currently-open log file, this does the wrong thing:
    # we really only want any new level to apply.
    #
    # (If mode is 'a', it's harmless to re-open it, and if
    # maxsize>0 the RotatingFileHandler changes the mode to 'a'.
    # In these cases we want to pick up any max-size or backup-count
    # changes as well.)
    fh = g.file_logger if mode == 'w' and maxsize == 0 else None
    if fh and fd_is_open_to(fh.stream.fileno(), filepath):
    pass # use it unchanged
    else:
    try:
    fh = logging.handlers.RotatingFileHandler(filepath, mode,
    maxsize, backup_count)
    fh.setFormatter(logging.Formatter(g.log_format))
    except IOError, e:
    logger.error('log to file: %s', e)
    errs = True
    fh = g.file_logger
    if fh:
    fh.setLevel(level)
    else:
    logger.debug('file logging suppressed')
    fh = None

    if not errs:
    # Swap out syslog and file loggers last, so that any previous
    # logging about syslog logging and file logging goes to the
    # old loggers (if any).
    g.syslog_logger = swapout(g.syslog_logger, sh)
    g.file_logger = swapout(g.file_logger, fh)

    return errs
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40?39.22'N, 111?50.29'W) +1 801 277 2603
    email: gmail (figure it out) http://web.torek.net/torek/index.html

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedOct 18, '10 at 6:52p
activeOct 19, '10 at 9:59a
posts5
users4
websitepython.org

People

Translate

site design / logo © 2022 Grokbase