Changeset 1261

Show
Ignore:
Timestamp:
04/27/06 11:37:50 (3 years ago)
Author:
kevin
Message:

much improved logging configuration

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.0/CHANGELOG.txt

    r1252 r1261  
    1616  permissionId to be user\_name, group\_name, and permission_name. 
    1717* visit\_id has been deprecated in favor of visit_key 
     18 
     19*Features* 
     20 
     21* Dramatically improved and unified logging configuration. Config files 
     22  can now use the options in Python's logging module for log formats 
     23  and output. 
    1824 
    1925*Changes* 
  • branches/1.0/setup.py

    r1214 r1261  
    4242        "cElementTree >= 1.0.5", "FormEncode >= 0.5.1", 
    4343        "setuptools >= 0.6a11", 
    44         "RuleDispatch", "nose >= 0.8"], 
     44        "RuleDispatch", "ConfigObj >= 4.3.0", "nose >= 0.8"], 
    4545    packages=find_packages(), 
    4646    include_package_data=True, 
  • branches/1.0/turbogears/config.py

    r1025 r1261  
    22 
    33from cherrypy import config 
     4from configobj import ConfigObj 
    45import pkg_resources 
    5 from cStringIO import StringIO 
     6import logging 
    67 
    78__all__ = ["update_config", "get", "update"] 
     
    1213    from sets import Set as set 
    1314 
     15class ConfigError(Exception): 
     16    pass 
     17 
     18def _get_formatters(formatters): 
     19    for key, formatter in formatters.items(): 
     20        kw = {} 
     21        fmt = formatter.get("format", None) 
     22        if fmt: 
     23            fmt = fmt.replace("*(", "%(") 
     24            kw["fmt"] = fmt 
     25        datefmt = formatter.get("datefmt", None) 
     26        if datefmt: 
     27            kw["datefmt"] = datefmt 
     28        formatter = logging.Formatter(**kw) 
     29        formatters[key] = formatter 
     30 
     31def _get_handlers(handlers, formatters): 
     32    for key, handler in handlers.items(): 
     33        kw = {} 
     34        cls = handler.get("class", None) 
     35        if not cls: 
     36            raise ConfigError("No class specified for logging handler %s"  
     37                              % key) 
     38        cls = eval(cls, logging.__dict__) 
     39        args = handler.get("args", tuple()) 
     40        if args: 
     41            args = eval(args, logging.__dict__) 
     42        handler_obj = cls(*args) 
     43        level = handler.get("level", None) 
     44        if level: 
     45            level = eval(level, logging.__dict__) 
     46            handler_obj.setLevel(level) 
     47        formatter = handler.get("formatter", None) 
     48        if formatter: 
     49            try: 
     50                formatter = formatters[formatter] 
     51            except KeyError: 
     52                raise ConfigError("Handler %s references unknown " 
     53                            "formatter %s" % (key, formatter)) 
     54            handler_obj.setFormatter(formatter) 
     55        handlers[key] = handler_obj 
     56 
     57def _get_loggers(loggers, handlers): 
     58    for key, logger in loggers.items(): 
     59        qualname = logger.get("qualname", None) 
     60        if qualname: 
     61            log = logging.getLogger(qualname) 
     62        else: 
     63            log = logging.getLogger() 
     64             
     65        level = logger.get("level", None) 
     66        if level: 
     67            level = eval(level, logging.__dict__) 
     68        else: 
     69            level = logging.NOTSET 
     70        log.setLevel(level) 
     71         
     72        propagate = logger.get("propagate", None) 
     73        if propagate is not None: 
     74            log.propagate = propagate 
     75         
     76        cfghandlers = logger.get("handlers", None) 
     77        if cfghandlers: 
     78            if isinstance(cfghandlers, basestring): 
     79                cfghandlers = [cfghandlers] 
     80            for handler in cfghandlers: 
     81                try: 
     82                    handler = handlers[handler] 
     83                except KeyError: 
     84                    raise ConfigError("Logger %s references unknown " 
     85                                "handler %s" % (key, handler)) 
     86                log.addHandler(handler) 
     87 
     88def configure_loggers(config): 
     89    """Configures the Python logging module, using options that are very 
     90    similar to the ones listed in the Python documentation. This also 
     91    removes the logging configuration from the configuration dictionary 
     92    because CherryPy doesn't like it there. Here are some of the Python 
     93    examples converted to the format used here: 
     94     
     95    [logging] 
     96    [[loggers]] 
     97    [[[parser]]] 
     98    [logger_parser] 
     99    level="DEBUG" 
     100    handlers="hand01" 
     101    propagate=1 
     102    qualname="compiler.parser" 
     103 
     104    [[handlers]] 
     105    [[[hand01]]] 
     106    class="StreamHandler" 
     107    level="NOTSET" 
     108    formatter="form01" 
     109    args="(sys.stdout,)" 
     110     
     111    [[formatters]] 
     112    [[[form01]]] 
     113    format="F1 *(asctime)s *(levelname)s *(message)s" 
     114    datefmt= 
     115     
     116     
     117    One notable format difference is that *() is used in the formatter 
     118    instead of %() because %() is already used for config file 
     119    interpolation. 
     120    """ 
     121    if not config.has_key("logging"): 
     122        config["global"]["tg.new_style_logging"] = False 
     123        return 
     124    logcfg = config["logging"] 
     125    formatters = logcfg.get("formatters", {}) 
     126    _get_formatters(formatters) 
     127     
     128    handlers = logcfg.get("handlers", {}) 
     129    _get_handlers(handlers, formatters) 
     130     
     131    loggers = logcfg.get("loggers", {}) 
     132    _get_loggers(loggers, handlers) 
     133     
     134    del config["logging"] 
     135    config["global"]["tg.new_style_logging"] = True 
    14136 
    15137def update_config(configfile = None, modulename = None): 
     
    33155        package_dir = pkg_resources.resource_filename( 
    34156                        packagename, "")[:-1].replace("\\", "/") 
    35         modconfig = config.dict_from_config_file(modfile,  
    36             vars=dict(top_level_dir=top_level_dir, 
    37                       package_dir=package_dir)) 
    38         config.update(modconfig) 
     157        configdata = ConfigObj(modfile, unrepr=True) 
     158        configdata.merge(dict(DEFAULT= dict(top_level_dir=top_level_dir, 
     159                                  package_dir=package_dir))) 
    39160 
    40161    if configfile: 
    41162        if modulename: 
    42             fileconfig = config.dict_from_config_file(configfile,  
    43                             vars=dict(top_level_dir=top_level_dir, 
    44                             package_dir=package_dir)) 
    45             config.update(fileconfig) 
     163            configdata2 = ConfigObj(configfile, unrepr=True) 
     164            configdata2['DEFAULT'] = configdata['DEFAULT'] 
     165            configdata.merge(configdata2) 
    46166        else: 
    47             config.update(file=configfile) 
     167            configdata = ConfigObj(configfile, unrepr=True) 
     168    configdict = configdata.dict() 
     169    configure_loggers(configdict) 
     170    config.update(configdict) 
    48171 
    49172def get(key, default_value=None, return_section=False, path = None): 
  • branches/1.0/turbogears/controllers.py

    r1136 r1261  
    307307    """ 
    308308    is_app_root = True 
     309     
     310    msglog = logging.getLogger('cherrypy.msg') 
     311    msglogfunc = {0: msglog.info, 1: msglog.warning, 2: msglog.error} 
     312    def _cp_log_message(self, msg, context = 'nocontext', severity = 0): 
     313        log = self.msglogfunc[severity] 
     314        text = ''.join((context, ': ', msg)) 
     315        log(text) 
     316     
     317    accesslog = logging.getLogger("turbogears.access") 
     318    def _cp_log_access(self): 
     319        tmpl = '%(h)s %(l)s %(u)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' 
     320        identity = getattr(cherrypy.request, "identity", None) 
     321        if not identity: 
     322            username = "-" 
     323        else: 
     324            username = identity.user_name 
     325        s = tmpl % {'h': cherrypy.request.remoteHost, 
     326                   'l': '-', 
     327                   'u': username, 
     328                   'r': cherrypy.request.requestLine, 
     329                   's': cherrypy.response.status.split(" ", 1)[0], 
     330                   'b': cherrypy.response.headers.get('Content-Length', 
     331                            '') or "-", 
     332                   'f': cherrypy.request.headers.get('referer', ''), 
     333                   'a': cherrypy.request.headers.get('user-agent', ''), 
     334        } 
     335        self.accesslog.info(s) 
    309336 
    310337Root = RootController 
  • branches/1.0/turbogears/qstemplates/quickstartbig/+package+/controllers/root.py_tmpl

    r996 r1261  
     1import logging 
     2 
    13import cherrypy 
     4 
    25import turbogears 
    3 from turbogears import controllers 
     6from turbogears import controllers, expose, redirect 
     7#if $identity != "none" 
    48from turbogears import identity 
     9#end if 
     10 
     11from ${package} import json 
     12 
     13log = logging.getLogger("${package}.controllers") 
    514 
    615class Root(controllers.RootController): 
    7     @turbogears.expose(template="${package}.templates.welcome") 
     16    @expose(template="${package}.templates.welcome") 
    817    def index(self): 
    918        import time 
     19        log.debug("Happy TurboGears Controller Responding For Duty") 
    1020        return dict(now=time.ctime()) 
    11          
    12     @turbogears.expose(html="${package}.templates.login") 
    13     def login(self, *args, **kw): 
    14         if hasattr(cherrypy.request, "identity_errors"): 
    15             msg= _("You must provide your credentials before accessing this resource.") 
    16             previous_url= cherrypy.request.path 
     21#if $identity != "none" 
     22 
     23    @expose(template="${package}.templates.login") 
     24    def login(self, forward_url=None, previous_url=None, *args, **kw): 
     25 
     26        if not identity.current.anonymous and identity.was_login_attempted(): 
     27            raise redirect(forward_url) 
     28 
     29        forward_url=None 
     30        previous_url= cherrypy.request.path 
     31 
     32        if identity.was_login_attempted(): 
     33            msg=_("The credentials you supplied were not correct or " 
     34                   "did not grant access to this resource.") 
     35        elif identity.get_identity_errors(): 
     36            msg=_("You must provide your credentials before accessing " 
     37                   "this resource.") 
    1738        else: 
    18             msg= _("Please log in.") 
    19             previous_url= cherrypy.request.headers.get("Referer", "/") 
     39            msg=_("Please log in.") 
     40            forward_url= cherrypy.request.headers.get("Referer", "/") 
    2041        cherrypy.response.status=403 
    2142        return dict(message=msg, previous_url=previous_url, logging_in=True, 
    22                      original_parameters=cherrypy.request.params) 
     43                    original_parameters=cherrypy.request.params, 
     44                    forward_url=forward_url) 
    2345 
    24     @turbogears.expose() 
     46    @expose() 
    2547    def logout(self): 
    2648        identity.current.logout() 
    27         raise cherrypy.HTTPRedirect(turbogears.url("/")) 
     49        raise redirect("/") 
     50#end if 
  • branches/1.0/turbogears/qstemplates/quickstart/dev.cfg_tmpl

    r1073 r1261  
    3636tg.strict_parameters = True 
    3737 
     38# LOGGING 
     39# Logging configuration generally follows the style of the standard 
     40# Python logging module configuration. Note that when specifying 
     41# log format messages, you need to use *() for formatting variables. 
     42[logging] 
     43 
     44[[formatters]] 
     45[[[messageonly]]] 
     46format='*(message)s' 
     47 
     48[[[fullcontent]]] 
     49format='*(asctime)s *(name)s *(levelname)s *(message)s' 
     50 
     51[[handlers]] 
     52[[[debugout]]] 
     53class='StreamHandler' 
     54level='DEBUG' 
     55args='(sys.stdout,)' 
     56formatter='fullcontent' 
     57 
     58[[[accessout]]] 
     59class='StreamHandler' 
     60level='INFO' 
     61args='(sys.stdout,)' 
     62formatter='messageonly' 
     63 
     64[[loggers]] 
     65[[[yourproject]]] 
     66level='DEBUG' 
     67qualname='${package}' 
     68handlers=['debugout'] 
     69 
     70[[[cherrymsg]]] 
     71level='INFO' 
     72qualname='cherrypy.msg' 
     73handlers=['debugout'] 
     74 
     75[[[access]]] 
     76level='INFO' 
     77qualname='turbogears.access' 
     78handlers=['accessout'] 
     79propagate=0 
  • branches/1.0/turbogears/qstemplates/quickstart/+package+/controllers.py_tmpl

    r1252 r1261  
     1import logging 
     2 
    13import cherrypy 
     4 
    25import turbogears 
    36from turbogears import controllers, expose, redirect 
     7#if $identity != "none" 
    48from turbogears import identity 
     9#end if 
    510 
    611from ${package} import json 
     12 
     13log = logging.getLogger("${package}.controllers") 
    714 
    815class Root(controllers.RootController): 
     
    1017    def index(self): 
    1118        import time 
     19        log.debug("Happy TurboGears Controller Responding For Duty") 
    1220        return dict(now=time.ctime()) 
    1321#if $identity != "none" 
  • branches/1.0/turbogears/qstemplates/quickstart/sample-prod.cfg_tmpl

    r1233 r1261  
    4040# tg.strict_parameters = False 
    4141 
     42# LOGGING 
     43# Logging configuration generally follows the style of the standard 
     44# Python logging module configuration. Note that when specifying 
     45# log format messages, you need to use *() for formatting variables. 
     46[logging] 
     47 
     48[[formatters]] 
     49[[[messageonly]]] 
     50format='*(message)s' 
     51 
     52[[handlers]] 
     53[[[errorout]]] 
     54class='StreamHandler' 
     55level='ERROR' 
     56args='(sys.stdout,)' 
     57 
     58[[[accessout]]] 
     59class='StreamHandler' 
     60level='INFO' 
     61args="('server.log',)" 
     62formatter='messageonly' 
     63 
     64[[loggers]] 
     65[[[yourproject]]] 
     66level='ERROR' 
     67qualname='${package}' 
     68handlers=['errorout'] 
     69 
     70[[[access]]] 
     71level='INFO' 
     72qualname='turbogears.access' 
     73handlers=['accessout'] 
     74propagate=0 
  • branches/1.0/turbogears/startup.py

    r1087 r1261  
    184184        webpath = webpath + "/" 
    185185    isdev = turbogears.config.get('server.environment') == 'development' 
    186     if turbogears.config.get('server.log_to_screen'): 
     186    if not turbogears.config.get("tg.new_style_logging") \ 
     187        and turbogears.config.get('server.log_to_screen'): 
     188         
    187189        log = logging.getLogger() 
    188190        log.setLevel(logging.DEBUG) 
     
    190192        handler = logging.StreamHandler(sys.stdout) 
    191193        handler.setLevel(logging.DEBUG) 
     194        handler.setFormatter(fmt) 
     195        log.addHandler(handler) 
     196         
     197        log = logging.getLogger("turbogears.access") 
     198        log.propagate = 0 
     199        fmt = logging.Formatter("%(message)s") 
     200        handler = logging.StreamHandler(sys.stdout) 
     201        handler.setLevel(logging.INFO) 
    192202        handler.setFormatter(fmt) 
    193203        log.addHandler(handler) 
  • branches/1.0/turbogears/tests/config.cfg

    r961 r1261  
    77[/static] 
    88static_filter.on = True 
     9 
     10[logging] 
     11[[formatters]] 
     12[[[coolformat]]] 
     13format="F1 *(asctime)s *(levelname)s *(message)s" 
     14datefmt= 
     15 
     16[[handlers]] 
     17[[[mystream]]] 
     18class='StreamHandler' 
     19level='NOTSET' 
     20formatter='coolformat' 
     21args='(logout,)' 
     22 
     23[[loggers]] 
     24[[[tester]]] 
     25level='DEBUG' 
     26handlers=['mystream'] 
     27propogate=1 
     28qualname="turbogears.tests.test_config.logconfig" 
  • branches/1.0/turbogears/tests/test_config.py

    r1025 r1261  
    11import turbogears 
    22import pkg_resources 
     3import sys 
     4from cStringIO import StringIO 
     5import logging 
     6import re 
    37 
    48testfile = pkg_resources.resource_filename(__name__, "configfile.cfg") 
    59 
    610rfn = pkg_resources.resource_filename 
     11 
     12logout = StringIO() 
     13logging.logout = logout 
    714 
    815def test_update_from_package(): 
     
    1724    turbogears.update_config(configfile = testfile,  
    1825        modulename="turbogears.tests.config") 
     26    print turbogears.config.get("foo.bar") 
    1927    assert turbogears.config.get("foo.bar") == "blurb" 
    2028    assert turbogears.config.get("tg.something") == 10 
     
    3947    print testdir 
    4048    assert testdir == "c:/foo/bar" 
     49 
     50def test_logging_config(): 
     51    logout.truncate(0) 
     52    log = logging.getLogger("turbogears.tests.test_config.logconfig") 
     53    log.info("Testing") 
     54    logged = logout.getvalue() 
     55    print "Logged: %s" % logged 
     56    assert re.match(r'F1 \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d,\d\d\d INFO ' 
     57                    'Testing', logged) 
     58    assert turbogears.config.get("tg.new_style_logging", False) 
    4159         
    4260def teardown_module():