#!/usr/bin/env python
#
# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of Vinay Sajip
# not be used in advertising or publicity pertaining to distribution
# of the software without specific, written prior permission.
# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# This file is part of the Python logging distribution. See
# http://www.red-dove.com/python_logging.html
#
"""
A test harness for the logging module. Tests arbitrary logging levels, filtering, and
use of strftime formatting.

Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
"""

import logging
import locale, sys

locale.setlocale(locale.LC_ALL, '')

def message(s):
    sys.stderr.write("%s\n" % s)

#
#   First, we define our levels. There can be as many as you want - the only limitations are that
#   they should be integers, the lowest should be > 0 and larger values mean less information being
#   logged. If you need specific level values which do not fit into these limitations, you can use
#   a mapping dictionary to convert between your application levels and the logging system.
#
SILENT      = 10
TACITURN    = 9
TERSE       = 8
EFFUSIVE    = 7
SOCIABLE    = 6
VERBOSE     = 5
TALKATIVE   = 4
GARRULOUS   = 3
CHATTERBOX  = 2
BORING      = 1

LEVEL_RANGE = range(BORING, SILENT + 1)

#
#   Next, we define names for our levels. You don't need to do this - in which case the system will
#   use "Level n" to denote the text for the level.
#
my_logging_levels = {
    SILENT      : 'Silent',
    TACITURN    : 'Taciturn',
    TERSE           : 'Terse',
    EFFUSIVE    : 'Effusive',
    SOCIABLE    : 'Sociable',
    VERBOSE     :   'Verbose',
    TALKATIVE   :   'Talkative',
    GARRULOUS   :   'Garrulous',
    CHATTERBOX: 'Chatterbox',
    BORING      :   'Boring',
}

#
#   Now, tell the logging system to associate names with our levels.
#
for lvl in my_logging_levels.keys():
    logging.addLevelName(lvl, my_logging_levels[lvl])

#
#   Now, define a test function which logs an event at each of our levels.
#
def doLog(log):
    for lvl in LEVEL_RANGE:
        log.log(lvl, "This should only be seen at the '%s' logging level (or lower)", logging.getLevelName(lvl))

#
#   Get the root logger and add a console hander to it, when run as a script.
#
log = logging.getLogger("")

if __name__ == "__main__":
    hdlr = logging.StreamHandler()
    hdlr.setFormatter(logging.Formatter("%(asctime)s %(message)s", "%X")) #date format is as per the locale
    log.addHandler(hdlr)
else:
    hdlr = log.handlers[0]
#
#   Set the logging level to each different value and call the utility function to log events.
#   In the output, you should see that each time round the loop, the logging events actually output
#   decreases.
#
for lvl in LEVEL_RANGE:
    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
    log.setLevel(lvl)
    doLog(log)
#
#   Now, we demonstrate level filtering at the handler level. Tell the handler defined above
#   to filter at level 'SOCIABLE', and repeat the above loop. Compare the output from the two runs.
#
hdlr.setLevel(SOCIABLE)
message("-- Filtering at handler level to SOCIABLE --")
for lvl in LEVEL_RANGE:
    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
    log.setLevel(lvl)
    doLog(log)

hdlr.setLevel(0)    #turn off level filtering at the handler

#
#   Now, let's demonstrate filtering. Suppose for some perverse reason we only want to print out
#   all except GARRULOUS messages. Let's create a filter for this purpose...
#
class SpecificLevelFilter(logging.Filter):
    def __init__(self, lvl):
        self.level = lvl

    def filter(self, record):
        return self.level != record.levelno

class GarrulousFilter(SpecificLevelFilter):
    def __init__(self):
        SpecificLevelFilter.__init__(self, GARRULOUS)

garr = GarrulousFilter()
hdlr.addFilter(garr)
message("-- Filtering using GARRULOUS filter --")
for lvl in LEVEL_RANGE:
    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
    log.setLevel(lvl)
    doLog(log)
#
#   Now, let's demonstrate filtering at the logger. This time, use a filter which excludes SOCIABLE
#   and TACITURN messages. Note that GARRULOUS events are still excluded.
#
class VerySpecificFilter(logging.Filter):
    def filter(self, record):
        return record.levelno not in [SOCIABLE, TACITURN]

spec = VerySpecificFilter()
log.addFilter(spec)
message("-- Filtering using specific filter for SOCIABLE, TACITURN --")
for lvl in LEVEL_RANGE:
    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
    log.setLevel(lvl)
    doLog(log)

log.removeFilter(spec)
hdlr.removeFilter(garr)
#Undo the one level which clashes...for regression tests
logging.addLevelName(logging.DEBUG, "DEBUG")

#
#   Er...that's it for now
#
if __name__ == "__main__":
    print "All done."
    logging.shutdown()

