Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd2c199

Browse files
committed
Merged cookbook update for LogRecord customisation.
2 parents 01121f2 + 982f534 commit bd2c199

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

Doc/howto/logging-cookbook.rst

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,88 @@ string. That's because the __ notation is just syntax sugar for a constructor
10921092
call to one of the XXXMessage classes.
10931093

10941094

1095+
.. currentmodule:: logging
1096+
1097+
.. custom-logrecord:
1098+
1099+
Customising ``LogRecord``
1100+
-------------------------
1101+
1102+
Every logging event is represented by a :class:`LogRecord` instance.
1103+
When an event is logged and not filtered out by a logger's level, a
1104+
:class:`LogRecord` is created, populated with information about the event and
1105+
then passed to the handlers for that logger (and its ancestors, up to and
1106+
including the logger where further propagation up the hierarchy is disabled).
1107+
Before Python 3.2, there were only two places where this creation was done:
1108+
1109+
* :meth:`Logger.makeRecord`, which is called in the normal process of
1110+
logging an event. This invoked :class:`LogRecord` directly to create an
1111+
instance.
1112+
* :func:`makeLogRecord`, which is called with a dictionary containing
1113+
attributes to be added to the LogRecord. This is typically invoked when a
1114+
suitable dictionary has been received over the network (e.g. in pickle form
1115+
via a :class:`~handlers.SocketHandler`, or in JSON form via an
1116+
:class:`~handlers.HTTPHandler`).
1117+
1118+
This has usually meant that if you need to do anything special with a
1119+
:class:`LogRecord`, you've had to do one of the following.
1120+
1121+
* Create your own :class:`Logger` subclass, which overrides
1122+
:meth:`Logger.makeRecord`, and set it using :func:`~logging.setLoggerClass`
1123+
before any loggers that you care about are instantiated.
1124+
* Add a :class:`Filter` to a logger or handler, which does the
1125+
necessary special manipulation you need when its
1126+
:meth:`~Filter.filter` method is called.
1127+
1128+
The first approach would be a little unwieldy in the scenario where (say)
1129+
several different libraries wanted to do different things. Each would attempt
1130+
to set its own :class:`Logger` subclass, and the one which did this last would
1131+
win.
1132+
1133+
The second approach works reasonably well for many cases, but does not allow
1134+
you to e.g. use a specialized subclass of :class:`LogRecord`. Library
1135+
developers can set a suitable filter on their loggers, but they would have to
1136+
remember to do this every time they introduced a new logger (which they would
1137+
do simply by adding new packages or modules and doing
1138+
1139+
.. code-block:: python
1140+
1141+
logger = logging.getLogger(__name__)
1142+
1143+
at module level). It's probably one too many things to think about. Developers
1144+
could also add the filter to a :class:`~logging.NullHandler` attached to their
1145+
top-level logger, but this would not be invoked if an application developer
1146+
attached a handler to a lower-level library logger – so output from that
1147+
handler would not reflect the intentions of the library developer.
1148+
1149+
In Python 3.2 and later, :class:`~logging.LogRecord` creation is done through a
1150+
factory, which you can specify. The factory is just a callable you can set with
1151+
:func:`~logging.setLogRecordFactory`, and interrogate with
1152+
:func:`~logging.getLogRecordFactory`. The factory is invoked with the same
1153+
signature as the :class:`~logging.LogRecord` constructor, as :class:`LogRecord`
1154+
is the default setting for the factory.
1155+
1156+
This approach allows a custom factory to control all aspects of LogRecord
1157+
creation. For example, you could return a subclass, or just add some additional
1158+
attributes to the record once created, using a pattern similar to this::
1159+
1160+
old_factory = logging.getLogRecordFactory()
1161+
1162+
def record_factory(*args, **kwargs):
1163+
record = old_factory(*args, **kwargs)
1164+
record.custom_attribute = 0xdecafbad
1165+
return record
1166+
1167+
logging.setLogRecordFactory(record_factory)
1168+
1169+
This pattern allows different libraries to chain factories together, and as
1170+
long as they don't overwrite each other's attributes or unintentionally
1171+
overwrite the attributes provided as standard, there should be no surprises.
1172+
However, it should be borne in mind that each link in the chain adds run-time
1173+
overhead to all logging operations, and the technique should only be used when
1174+
the use of a :class:`Filter` does not provide the desired result.
1175+
1176+
10951177
.. _zeromq-handlers:
10961178

10971179
Subclassing QueueHandler - a ZeroMQ example

0 commit comments

Comments
 (0)