@@ -1692,6 +1692,9 @@ When the above script is run, it prints::
16921692Note that the order of items might be different according to the version of
16931693Python used.
16941694
1695+
1696+ .. _custom-handlers :
1697+
16951698.. currentmodule :: logging.config
16961699
16971700Customizing handlers with :func: `dictConfig `
@@ -1946,3 +1949,87 @@ handler. So the only slightly unusual thing which might trip you up is that the
19461949parentheses go around the format string and the arguments, not just the format
19471950string. That’s because the __ notation is just syntax sugar for a constructor
19481951call to one of the ``XXXMessage `` classes shown above.
1952+
1953+
1954+ .. _filters-dictconfig :
1955+
1956+ .. currentmodule :: logging.config
1957+
1958+ Configuring filters with :func: `dictConfig `
1959+ -------------------------------------------
1960+
1961+ You *can * configure filters using :func: `~logging.config.dictConfig `, though it
1962+ might not be obvious at first glance how to do it (hence this recipe). Since
1963+ :class: `~logging.Filter ` is the only filter class included in the standard
1964+ library, and it is unlikely to cater to many requirements (it's only there as a
1965+ base class), you will typically need to define your own :class: `~logging.Filter `
1966+ subclass with an overridden :meth: `~logging.Filter.filter ` method. To do this,
1967+ specify the ``() `` key in the configuration dictionary for the filter,
1968+ specifying a callable which will be used to create the filter (a class is the
1969+ most obvious, but you can provide any callable which returns a
1970+ :class: `~logging.Filter ` instance). Here is a complete example::
1971+
1972+ import logging
1973+ import logging.config
1974+ import sys
1975+
1976+ class MyFilter(logging.Filter):
1977+ def __init__(self, param=None):
1978+ self.param = param
1979+
1980+ def filter(self, record):
1981+ if self.param is None:
1982+ allow = True
1983+ else:
1984+ allow = self.param not in record.msg
1985+ if allow:
1986+ record.msg = 'changed: ' + record.msg
1987+ return allow
1988+
1989+ LOGGING = {
1990+ 'version': 1,
1991+ 'filters': {
1992+ 'myfilter': {
1993+ '()': MyFilter,
1994+ 'param': 'noshow',
1995+ }
1996+ },
1997+ 'handlers': {
1998+ 'console': {
1999+ 'class': 'logging.StreamHandler',
2000+ 'filters': ['myfilter']
2001+ }
2002+ },
2003+ 'root': {
2004+ 'level': 'DEBUG',
2005+ 'handlers': ['console']
2006+ },
2007+ }
2008+
2009+ if __name__ == '__main__':
2010+ logging.config.dictConfig(LOGGING)
2011+ logging.debug('hello')
2012+ logging.debug('hello - noshow')
2013+
2014+ This example shows how you can pass configuration data to the callable which
2015+ constructs the instance, in the form of keyword parameters. When run, the above
2016+ script will print::
2017+
2018+ changed: hello
2019+
2020+ which shows that the filter is working as configured.
2021+
2022+ A couple of extra points to note:
2023+
2024+ * If you can't refer to the callable directly in the configuration (e.g. if it
2025+ lives in a different module, and you can't import it directly where the
2026+ configuration dictionary is), you can use the form ``ext://... `` as described
2027+ in :ref: `logging-config-dict-externalobj `. For example, you could have used
2028+ the text ``'ext://__main__.MyFilter' `` instead of ``MyFilter `` in the above
2029+ example.
2030+
2031+ * As well as for filters, this technique can also be used to configure custom
2032+ handlers and formatters. See :ref: `logging-config-dict-userdef ` for more
2033+ information on how logging supports using user-defined objects in its
2034+ configuration, and see the other cookbook recipe :ref: `custom-handlers ` above.
2035+
0 commit comments