Skip to content

Commit ca7b504

Browse files
authored
bpo-37111: Add 'encoding' and 'errors' parameters to logging.basicCon… (GH-14008)
1 parent 00f6493 commit ca7b504

File tree

8 files changed

+197
-27
lines changed

8 files changed

+197
-27
lines changed

Doc/howto/logging.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,18 @@ look at that next. Be sure to try the following in a newly-started Python
128128
interpreter, and don't just continue from the session described above::
129129

130130
import logging
131-
logging.basicConfig(filename='example.log',level=logging.DEBUG)
131+
logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)
132132
logging.debug('This message should go to the log file')
133133
logging.info('So should this')
134134
logging.warning('And this, too')
135+
logging.error('And non-ASCII stuff, too, like Øresund and Malmö')
136+
137+
.. versionchanged:: 3.9
138+
The *encoding* argument was added. In earlier Python versions, or if not
139+
specified, the encoding used is the default value used by :func:`open`. While
140+
not shown in the above example, an *errors* argument can also now be passed,
141+
which determines how encoding errors are handled. For available values and
142+
the default, see the documentation for :func:`open`.
135143

136144
And now if we open the file and look at what we have, we should find the log
137145
messages:
@@ -141,6 +149,7 @@ messages:
141149
DEBUG:root:This message should go to the log file
142150
INFO:root:So should this
143151
WARNING:root:And this, too
152+
ERROR:root:And non-ASCII stuff, too, like Øresund and Malmö
144153
145154
This example also shows how you can set the logging level which acts as the
146155
threshold for tracking. In this case, because we set the threshold to

Doc/library/logging.handlers.rst

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,22 @@ sends logging output to a disk file. It inherits the output functionality from
8989
:class:`StreamHandler`.
9090

9191

92-
.. class:: FileHandler(filename, mode='a', encoding=None, delay=False)
92+
.. class:: FileHandler(filename, mode='a', encoding=None, delay=False, errors=None)
9393

9494
Returns a new instance of the :class:`FileHandler` class. The specified file is
9595
opened and used as the stream for logging. If *mode* is not specified,
9696
:const:`'a'` is used. If *encoding* is not ``None``, it is used to open the file
9797
with that encoding. If *delay* is true, then file opening is deferred until the
98-
first call to :meth:`emit`. By default, the file grows indefinitely.
98+
first call to :meth:`emit`. By default, the file grows indefinitely. If
99+
*errors* is specified, it's used to determine how encoding errors are handled.
99100

100101
.. versionchanged:: 3.6
101102
As well as string values, :class:`~pathlib.Path` objects are also accepted
102103
for the *filename* argument.
103104

105+
.. versionchanged:: 3.9
106+
The *errors* parameter was added.
107+
104108
.. method:: close()
105109

106110
Closes the file.
@@ -168,18 +172,22 @@ exclusive locks - and so there is no need for such a handler. Furthermore,
168172
for this value.
169173

170174

171-
.. class:: WatchedFileHandler(filename, mode='a', encoding=None, delay=False)
175+
.. class:: WatchedFileHandler(filename, mode='a', encoding=None, delay=False, errors=None)
172176

173177
Returns a new instance of the :class:`WatchedFileHandler` class. The specified
174178
file is opened and used as the stream for logging. If *mode* is not specified,
175179
:const:`'a'` is used. If *encoding* is not ``None``, it is used to open the file
176180
with that encoding. If *delay* is true, then file opening is deferred until the
177-
first call to :meth:`emit`. By default, the file grows indefinitely.
181+
first call to :meth:`emit`. By default, the file grows indefinitely. If
182+
*errors* is provided, it determines how encoding errors are handled.
178183

179184
.. versionchanged:: 3.6
180185
As well as string values, :class:`~pathlib.Path` objects are also accepted
181186
for the *filename* argument.
182187

188+
.. versionchanged:: 3.9
189+
The *errors* parameter was added.
190+
183191
.. method:: reopenIfNeeded()
184192

185193
Checks to see if the file has changed. If it has, the existing stream is
@@ -205,7 +213,7 @@ module, is the base class for the rotating file handlers,
205213
not need to instantiate this class, but it has attributes and methods you may
206214
need to override.
207215

208-
.. class:: BaseRotatingHandler(filename, mode, encoding=None, delay=False)
216+
.. class:: BaseRotatingHandler(filename, mode, encoding=None, delay=False, errors=None)
209217

210218
The parameters are as for :class:`FileHandler`. The attributes are:
211219

@@ -284,13 +292,14 @@ The :class:`RotatingFileHandler` class, located in the :mod:`logging.handlers`
284292
module, supports rotation of disk log files.
285293

286294

287-
.. class:: RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)
295+
.. class:: RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False, errors=None)
288296

289297
Returns a new instance of the :class:`RotatingFileHandler` class. The specified
290298
file is opened and used as the stream for logging. If *mode* is not specified,
291299
``'a'`` is used. If *encoding* is not ``None``, it is used to open the file
292300
with that encoding. If *delay* is true, then file opening is deferred until the
293-
first call to :meth:`emit`. By default, the file grows indefinitely.
301+
first call to :meth:`emit`. By default, the file grows indefinitely. If
302+
*errors* is provided, it determines how encoding errors are handled.
294303

295304
You can use the *maxBytes* and *backupCount* values to allow the file to
296305
:dfn:`rollover` at a predetermined size. When the size is about to be exceeded,
@@ -311,6 +320,9 @@ module, supports rotation of disk log files.
311320
As well as string values, :class:`~pathlib.Path` objects are also accepted
312321
for the *filename* argument.
313322

323+
.. versionchanged:: 3.9
324+
The *errors* parameter was added.
325+
314326
.. method:: doRollover()
315327

316328
Does a rollover, as described above.
@@ -331,7 +343,7 @@ The :class:`TimedRotatingFileHandler` class, located in the
331343
timed intervals.
332344

333345

334-
.. class:: TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None)
346+
.. class:: TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None, errors=None)
335347

336348
Returns a new instance of the :class:`TimedRotatingFileHandler` class. The
337349
specified file is opened and used as the stream for logging. On rotating it also
@@ -391,6 +403,9 @@ timed intervals.
391403
rollover, and subsequent rollovers would be calculated via the normal
392404
interval calculation.
393405

406+
If *errors* is specified, it's used to determine how encoding errors are
407+
handled.
408+
394409
.. note:: Calculation of the initial rollover time is done when the handler
395410
is initialised. Calculation of subsequent rollover times is done only
396411
when rollover occurs, and rollover occurs only when emitting output. If
@@ -411,6 +426,9 @@ timed intervals.
411426
As well as string values, :class:`~pathlib.Path` objects are also accepted
412427
for the *filename* argument.
413428

429+
.. versionchanged:: 3.9
430+
The *errors* parameter was added.
431+
414432
.. method:: doRollover()
415433

416434
Does a rollover, as described above.

Doc/library/logging.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,21 @@ functions.
11961196
| | carrying out the configuration as specified |
11971197
| | by the other arguments. |
11981198
+--------------+---------------------------------------------+
1199+
| *encoding* | If this keyword argument is specified along |
1200+
| | with *filename*, its value is used when the |
1201+
| | FileHandler is created, and thus used when |
1202+
| | opening the output file. |
1203+
+--------------+---------------------------------------------+
1204+
| *errors* | If this keyword argument is specified along |
1205+
| | with *filename*, its value is used when the |
1206+
| | FileHandler is created, and thus used when |
1207+
| | opening the output file. If not specified, |
1208+
| | the value 'backslashreplace' is used. Note |
1209+
| | that if ``None`` is specified, it will be |
1210+
| | passed as such to func:`open`, which means |
1211+
| | that it will be treated the same as passing |
1212+
| | 'errors'. |
1213+
+--------------+---------------------------------------------+
11991214

12001215
.. versionchanged:: 3.2
12011216
The *style* argument was added.
@@ -1209,6 +1224,9 @@ functions.
12091224
.. versionchanged:: 3.8
12101225
The *force* argument was added.
12111226

1227+
.. versionchanged:: 3.9
1228+
The *encoding* and *errors* arguments were added.
1229+
12121230
.. function:: shutdown()
12131231

12141232
Informs the logging system to perform an orderly shutdown by flushing and

Doc/tools/susp-ignored.csv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ howto/ipaddress,,::,IPv6Address('2001:db8::ffff:ffff')
8181
howto/ipaddress,,:ffff,IPv6Address('2001:db8::ffff:ffff')
8282
howto/logging,,:And,"WARNING:And this, too"
8383
howto/logging,,:And,"WARNING:root:And this, too"
84+
howto/logging,,:And,"ERROR:root:And non-ASCII stuff, too, like "
8485
howto/logging,,:Doing,INFO:root:Doing something
8586
howto/logging,,:Finished,INFO:root:Finished
8687
howto/logging,,:logger,severity:logger name:message
@@ -90,6 +91,7 @@ howto/logging,,:root,DEBUG:root:This message should go to the log file
9091
howto/logging,,:root,INFO:root:Doing something
9192
howto/logging,,:root,INFO:root:Finished
9293
howto/logging,,:root,INFO:root:So should this
94+
howto/logging,,:root,"ERROR:root:And non-ASCII stuff, too, like "
9395
howto/logging,,:root,INFO:root:Started
9496
howto/logging,,:root,"WARNING:root:And this, too"
9597
howto/logging,,:root,WARNING:root:Look before you leap!

Lib/logging/__init__.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2001-2017 by Vinay Sajip. All Rights Reserved.
1+
# Copyright 2001-2019 by Vinay Sajip. All Rights Reserved.
22
#
33
# Permission to use, copy, modify, and distribute this software and its
44
# documentation for any purpose and without fee is hereby granted,
@@ -18,7 +18,7 @@
1818
Logging package for Python. Based on PEP 282 and comments thereto in
1919
comp.lang.python.
2020
21-
Copyright (C) 2001-2017 Vinay Sajip. All Rights Reserved.
21+
Copyright (C) 2001-2019 Vinay Sajip. All Rights Reserved.
2222
2323
To use, simply 'import logging' and log away!
2424
"""
@@ -1122,7 +1122,7 @@ class FileHandler(StreamHandler):
11221122
"""
11231123
A handler class which writes formatted logging records to disk files.
11241124
"""
1125-
def __init__(self, filename, mode='a', encoding=None, delay=False):
1125+
def __init__(self, filename, mode='a', encoding=None, delay=False, errors=None):
11261126
"""
11271127
Open the specified file and use it as the stream for logging.
11281128
"""
@@ -1133,6 +1133,7 @@ def __init__(self, filename, mode='a', encoding=None, delay=False):
11331133
self.baseFilename = os.path.abspath(filename)
11341134
self.mode = mode
11351135
self.encoding = encoding
1136+
self.errors = errors
11361137
self.delay = delay
11371138
if delay:
11381139
#We don't open the stream, but we still need to call the
@@ -1169,7 +1170,8 @@ def _open(self):
11691170
Open the current base file with the (original) mode and encoding.
11701171
Return the resulting stream.
11711172
"""
1172-
return open(self.baseFilename, self.mode, encoding=self.encoding)
1173+
return open(self.baseFilename, self.mode, encoding=self.encoding,
1174+
errors=self.errors)
11731175

11741176
def emit(self, record):
11751177
"""
@@ -1928,15 +1930,20 @@ def basicConfig(**kwargs):
19281930
attached to the root logger are removed and closed, before
19291931
carrying out the configuration as specified by the other
19301932
arguments.
1933+
encoding If specified together with a filename, this encoding is passed to
1934+
the created FileHandler, causing it to be used when the file is
1935+
opened.
1936+
errors If specified together with a filename, this value is passed to the
1937+
created FileHandler, causing it to be used when the file is
1938+
opened in text mode. If not specified, the default value is
1939+
`backslashreplace`.
1940+
19311941
Note that you could specify a stream created using open(filename, mode)
19321942
rather than passing the filename and mode in. However, it should be
19331943
remembered that StreamHandler does not close its stream (since it may be
19341944
using sys.stdout or sys.stderr), whereas FileHandler closes its stream
19351945
when the handler is closed.
19361946
1937-
.. versionchanged:: 3.8
1938-
Added the ``force`` parameter.
1939-
19401947
.. versionchanged:: 3.2
19411948
Added the ``style`` parameter.
19421949
@@ -1946,12 +1953,20 @@ def basicConfig(**kwargs):
19461953
``filename``/``filemode``, or ``filename``/``filemode`` specified
19471954
together with ``stream``, or ``handlers`` specified together with
19481955
``stream``.
1956+
1957+
.. versionchanged:: 3.8
1958+
Added the ``force`` parameter.
1959+
1960+
.. versionchanged:: 3.9
1961+
Added the ``encoding`` and ``errors`` parameters.
19491962
"""
19501963
# Add thread safety in case someone mistakenly calls
19511964
# basicConfig() from multiple threads
19521965
_acquireLock()
19531966
try:
19541967
force = kwargs.pop('force', False)
1968+
encoding = kwargs.pop('encoding', None)
1969+
errors = kwargs.pop('errors', 'backslashreplace')
19551970
if force:
19561971
for h in root.handlers[:]:
19571972
root.removeHandler(h)
@@ -1970,7 +1985,10 @@ def basicConfig(**kwargs):
19701985
filename = kwargs.pop("filename", None)
19711986
mode = kwargs.pop("filemode", 'a')
19721987
if filename:
1973-
h = FileHandler(filename, mode)
1988+
if 'b'in mode:
1989+
errors = None
1990+
h = FileHandler(filename, mode,
1991+
encoding=encoding, errors=errors)
19741992
else:
19751993
stream = kwargs.pop("stream", None)
19761994
h = StreamHandler(stream)

Lib/logging/handlers.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,16 @@ class BaseRotatingHandler(logging.FileHandler):
4848
Not meant to be instantiated directly. Instead, use RotatingFileHandler
4949
or TimedRotatingFileHandler.
5050
"""
51-
def __init__(self, filename, mode, encoding=None, delay=False):
51+
def __init__(self, filename, mode, encoding=None, delay=False, errors=None):
5252
"""
5353
Use the specified filename for streamed logging
5454
"""
55-
logging.FileHandler.__init__(self, filename, mode, encoding, delay)
55+
logging.FileHandler.__init__(self, filename, mode=mode,
56+
encoding=encoding, delay=delay,
57+
errors=errors)
5658
self.mode = mode
5759
self.encoding = encoding
60+
self.errors = errors
5861
self.namer = None
5962
self.rotator = None
6063

@@ -117,7 +120,8 @@ class RotatingFileHandler(BaseRotatingHandler):
117120
Handler for logging to a set of files, which switches from one file
118121
to the next when the current file reaches a certain size.
119122
"""
120-
def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False):
123+
def __init__(self, filename, mode='a', maxBytes=0, backupCount=0,
124+
encoding=None, delay=False, errors=None):
121125
"""
122126
Open the specified file and use it as the stream for logging.
123127
@@ -145,7 +149,8 @@ def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None,
145149
# on each run.
146150
if maxBytes > 0:
147151
mode = 'a'
148-
BaseRotatingHandler.__init__(self, filename, mode, encoding, delay)
152+
BaseRotatingHandler.__init__(self, filename, mode, encoding=encoding,
153+
delay=delay, errors=errors)
149154
self.maxBytes = maxBytes
150155
self.backupCount = backupCount
151156

@@ -196,8 +201,11 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
196201
If backupCount is > 0, when rollover is done, no more than backupCount
197202
files are kept - the oldest ones are deleted.
198203
"""
199-
def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None):
200-
BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay)
204+
def __init__(self, filename, when='h', interval=1, backupCount=0,
205+
encoding=None, delay=False, utc=False, atTime=None,
206+
errors=None):
207+
BaseRotatingHandler.__init__(self, filename, 'a', encoding=encoding,
208+
delay=delay, errors=errors)
201209
self.when = when.upper()
202210
self.backupCount = backupCount
203211
self.utc = utc
@@ -431,8 +439,11 @@ class WatchedFileHandler(logging.FileHandler):
431439
This handler is based on a suggestion and patch by Chad J.
432440
Schroeder.
433441
"""
434-
def __init__(self, filename, mode='a', encoding=None, delay=False):
435-
logging.FileHandler.__init__(self, filename, mode, encoding, delay)
442+
def __init__(self, filename, mode='a', encoding=None, delay=False,
443+
errors=None):
444+
logging.FileHandler.__init__(self, filename, mode=mode,
445+
encoding=encoding, delay=delay,
446+
errors=errors)
436447
self.dev, self.ino = -1, -1
437448
self._statstream()
438449

0 commit comments

Comments
 (0)