@@ -1092,6 +1092,88 @@ string. That's because the __ notation is just syntax sugar for a constructor
10921092call 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
10971179Subclassing QueueHandler - a ZeroMQ example
0 commit comments