Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Changes between Version 6 and Version 7 of logging


Ignore:
Timestamp:
06/07/06 18:40:00 (13 years ago)
Author:
Kaan
Comment:

Finished!

Legend:

Unmodified
Added
Removed
Modified
  • logging

    v6 v7  
    3737 
    3838= TurboGears .cfg files = 
    39 if you are used to the "normal" way of creating loggers, either by logging.basicConfig or [http://docs.python.org/lib/logging-config-fileformat.html config files] you may get confused by this format. 
     39If you are used to the "normal" way of creating loggers, either by [http://docs.python.org/lib/logging-config-api.html loggingConfig] or [http://docs.python.org/lib/logging-config-fileformat.html config files] you may get confused by this format. 
    4040 
    41 So lets start with the format this is a ConfigObj and its format is at [http://www.voidspace.org.uk/python/configobj.html#the-config-file-format ConfigObj File Format] for you the framework user the only diference from [http://docs.python.org/lib/module-ConfigParser.html ConfigParser] is the extra nested tags and by now you should know that those generate a dict inside another. On the other hand if you want to explore the goodies of ConfigObj Here are the [http://www.voidspace.org.uk/python/configobj.html docs] 
    42  
    43 by the way if you ever want to store python type in a config file [http://www.voidspace.org.uk/python/configobj.html#unrepr-mode unrepr] is what you need which is exactly what TG is doing and yes those are format strings and python lists on the default log.cfg 
     41So lets start with the format. This config file is read by ConfigObj and you can check out the documentation for the  [http://www.voidspace.org.uk/python/configobj.html#the-config-file-format ConfigObj File Format] for more detail. For our purposes here the only diference from standard library [http://docs.python.org/lib/module-ConfigParser.html ConfigParser] is the nested tags, which will generate a dictionary of the tag name and fill it with whatevers in that nested section. If you want to explore the goodness of ConfigObj, take a look at the  [http://www.voidspace.org.uk/python/configobj.html docs], especially the part about storing python types in a config file [http://www.voidspace.org.uk/python/configobj.html#unrepr-mode storing python types in a config file], which might clear up what's going on in the default [wiki:logging#inlog.cfg log.cfg]. 
    4442 
    4543== What is this *()  == 
    46 think of it as %() 
    47 === Why change it? === 
    48 http://trac.turbogears.org/turbogears/browser/tags/0.9a5/turbogears/config.py#L117 and if you still dont believe me  
    49 http://trac.turbogears.org/turbogears/browser/tags/0.9a5/turbogears/config.py#L23 now can we go on? 
     44Think of it as `%()` since we can't put it into a config file, as ConfigObj interprets it as something else. Just a [source:/tags/0.9a5/turbogears/config.py#L117 slight] [source:/browser/tags/0.9a5/turbogears/config.py#L23 hack], nothing to see here, move along... 
    5045 
    51 == logging format == 
    52 So the file log.cfg file always starts with  
     46== Logging Config Format == 
     47In your config files, always start the logging specific stuff with: 
    5348{{{ 
    5449[logging] 
    5550}}} 
    5651 
    57 and there is a section in dev/prod.cfg with the same name, they are all load up into the same dict so in practice defining things in either is ok. 
     52like in dev/prod.cfg.  They'll all load up into the same dict thanks to ConfigObj so in practice defining things in either file is ok. 
    5853 
    59 This is the head if the logging cfg, if we ever more this to other file the core will still work thanks to configObj 
    60  
    61 then you have 3 sections  
     54When all is said and done, you have 3 sections defined ''somewhere'' in your config files like so: 
    6255{{{ 
    6356[[formatters]] 
     
    6659}}} 
    6760 
    68 where all are optional although you should at least have "handlers" and "loggers" 
    69 after this all lvl 3 are just names which as all dict keys and therefore must be unique 
     61While all three are technically optional, it's recommended you have at least the "handlers" and "loggers" sections. 
    7062 
    71 == Formatters == 
    72 === format key === 
    73 each lvl 3 aggregate should have only one key call format which becomes the fmt param of a [http://docs.python.org/lib/node357.html Formatter Object], there you can see all the possible values this can have, as well as what happens went ommited 
     63Let's go over these sections and their keys and what they do. Remember that these will be read into the dictionary as keyword arguments, so make sure you keep them unique: 
    7464 
    75 == handlers == 
    76 === class key === 
    77 each handler must have at least a class key which has to be one of [http://docs.python.org/lib/node345.html Handler Objects] and yes you can subclass it but I think you will have enough with the defaults, also TG will error out since your class is not part of logging.__dict__ 
    78 === args key === 
    79 the "optional" args key are the parameters pass to each subclass of Handler 
    80 === level key === 
    81 the level key indicates the loggin level of this handler this can be any of the default levels DEBUG, INFO, WARNING, ERROR and CRITICAL or a string with the number, i got a patch to fix this TODO summit patch 
    82 === formatter key === 
    83 formatter any lvl 3 name form formatters  
    84 if level is ommited level=NOTSET if formatter is omitted the default is used '%(message)s' 
     65=== Formatters === 
     66Each subsection within this section should have only one key as per the following: 
    8567 
    86 {{{ 
    87 ... 
    88 [[[full_content]]] 
    89 format='*(asctime)s *(name)s *(levelname)s *(message)s' 
    90 ... 
    91 [[[debug_out]]] 
    92 class='StreamHandler' 
    93 level='DEBUG' 
    94 args='(sys.stdout,)' 
    95 formatter='full_content' 
    96 }}} 
    97 So now this makes sence We are creating a StreamHandler to sys.stdout with lvl debug using the formatted defined above  
     68`format` 
     69  The format string which initializes a [http://docs.python.org/lib/node357.html Formatter Object]. Just like in the standard docs but remember to replace `%(` with `*(` like we talked about [wiki:logging#Whatisthis above]. 
    9870 
    99 == loggers == 
    100 This is a another way to create [http://docs.python.org/lib/node341.html Logger Objects]  You can either define them here or do the calls in your code, it depends on your situation/taste there for I'll make a reference to the method call and you will know how to do it both ways and I'll type it ones 
    101 === qualname === 
    102 name of this logger 
     71== Handlers == 
     72Each subsection within this section is required to have a class key. 
     73 
     74`class` 
     75  Should be one of the [http://docs.python.org/lib/node345.html Handler Objects] or a subclass thereof. If you subclass you might get some errors from TG since your class is not in logging.__dict__ 
     76 
     77`args` 
     78  Parameters pass to each subclass of Handler and will vary based on which on you pick. 
     79 
     80`level` 
     81  Indicates the logging level of this handler and can be any of the default levels DEBUG, INFO, WARNING, ERROR and CRITICAL. With a patch it can also be a string with a level number (Is this fixed yet?). Defaults to NOTSET.  
     82 
     83`formatter` 
     84  Can be the name of any subsection that you defined under the [wiki:logging#Formatters formatters] section. Defaults to `%(message)s` 
     85 
     86== Loggers == 
     87This is a another way to create [http://docs.python.org/lib/node341.html Logger Objects].  You can either define them here or do the calls in your code, it depends on your situation/taste. Code accomplishing the same thing follow the descriptions of the parameters. 
     88 
     89`qualname` 
     90  Name of the logger 
     91 
    10392{{{ 
    10493if qualname: 
     
    10796log=logging.getLogger() 
    10897}}} 
    109 === level ===  
     98 
     99`level` 
     100  The level threshold for this handler. Levels less severe than this will be ignored. 
     101 
    110102{{{ 
    111103log.setLevel(level) 
    112104}}} 
    113 === handlers ===  
    114 handlers is a list so  
     105 
     106`handlers` 
     107  Equivalent to calling the addhandler method of a [http://docs.python.org/lib/node341.html logger object]. Useful for sending logs to multiple places. 
     108 
    115109{{{ 
    116110for handler in handlers: 
    117111 log.addHandlers(handler) 
    118112}}} 
    119 === propagate ===  
     113 
     114`propagate` 
     115  Same as the propagate class attribute of a [http://docs.python.org/lib/node341.html logger object]. Sets whether or not log messages are passed to parent loggers. Defaults to 1. 
     116 
    120117{{{ 
    121118log.propagate=propagate 
    122119}}} 
    123120 
    124 And no those are "examples" it's not the way TG does it. 
    125121 
    126122== Putting it all together == 
     123But these examples are not the way TurboGears does it, so let's take a look at how it does! We'll go through file by file. 
    127124 
    128 === in log.cfg === 
     125=== log.cfg === 
    129126 
    130127{{{ 
     
    156153}}} 
    157154 
    158 We define 2 formatters named "message_only" and "full_content", then we define 3 handlers which all Stream to stdout with diferent levels and using the two formaters we define. 
    159 === In dev.cfg === 
     155Can you follow it yet? We define 2 formatters named "message_only" and "full_content", then we pick 3 handlers which all stream to stdout but with different levels and using the two formaters we defined in the same file. 
     156 
     157=== dev.cfg === 
    160158{{{ 
    161159[logging] 
    162160 
    163161[[loggers]] 
    164 [[[your_project]]] 
     162[[[<your_package>]]] 
    165163level='DEBUG' 
    166164qualname='<your package>' 
     
    178176}}} 
    179177 
    180 We define 3 loggers "your_project" which is the one we use at the start of this tutorial that prints DEBUG messages to stdout, "allinfo" which is the main logger (notice missing qualname) and "access" that prints INFO messages to stdout. 
     178Here we create 3 loggers:  
    181179 
    182 NOTE: "your_project" is no longer there as of r1367 and 0.9a6, it was a "typo"  
     180 * '''your_project''' - The one we used at the start of this tutorial, prints DEBUG messages to stdout 
     181 * '''allinfo''' - The main logger (note the missing qualname) 
     182 * '''access''' - Prints INFO messages to stdout. 
    183183 
    184 = What now = 
     184= Conclusion = 
    185185 
    186 Now that you finally undestand how it works it's time to turn it around and do lots of stuff with it check out LoggingConfigurationExamples. 
     186Now that you undestand how it works it's time to turn it around and do lots of stuff with it. Check out LoggingConfigurationExamples for more. 
    187187 
    188 = Custom level Logging = 
    189188TODO add patch to add custom levels