Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
dde9fdbe
Unverified
Kaydet (Commit)
dde9fdbe
authored
Haz 05, 2018
tarafından
Vinay Sajip
Kaydeden (comit)
GitHub
Haz 05, 2018
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
bpo-33165: Added stacklevel parameter to logging APIs. (GH-7424)
üst
9ef1b069
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
77 additions
and
19 deletions
+77
-19
logging.rst
Doc/library/logging.rst
+34
-16
__init__.py
Lib/logging/__init__.py
+10
-3
test_logging.py
Lib/test/test_logging.py
+31
-0
2018-06-05-12-43-25.bpo-33165.9TIsVf.rst
...S.d/next/Library/2018-06-05-12-43-25.bpo-33165.9TIsVf.rst
+2
-0
No files found.
Doc/library/logging.rst
Dosyayı görüntüle @
dde9fdbe
...
@@ -160,8 +160,8 @@ is the module's name in the Python package namespace.
...
@@ -160,8 +160,8 @@ is the module's name in the Python package namespace.
*msg* using the string formatting operator. (Note that this means that you can
*msg* using the string formatting operator. (Note that this means that you can
use keywords in the format string, together with a single dictionary argument.)
use keywords in the format string, together with a single dictionary argument.)
There are
three
keyword arguments in *kwargs* which are inspected:
There are
four
keyword arguments in *kwargs* which are inspected:
*exc_info*, *stack_info*, and *extra*.
*exc_info*, *stack_info*,
*stacklevel*
and *extra*.
If *exc_info* does not evaluate as false, it causes exception information to be
If *exc_info* does not evaluate as false, it causes exception information to be
added to the logging message. If an exception tuple (in the format returned by
added to the logging message. If an exception tuple (in the format returned by
...
@@ -188,11 +188,19 @@ is the module's name in the Python package namespace.
...
@@ -188,11 +188,19 @@ is the module's name in the Python package namespace.
This mimics the ``Traceback (most recent call last):`` which is used when
This mimics the ``Traceback (most recent call last):`` which is used when
displaying exception frames.
displaying exception frames.
The third keyword argument is *extra* which can be used to pass a
The third optional keyword argument is *stacklevel*, which defaults to ``1``.
dictionary which is used to populate the __dict__ of the LogRecord created for
If greater than 1, the corresponding number of stack frames are skipped
the logging event with user-defined attributes. These custom attributes can then
when computing the line number and function name set in the :class:`LogRecord`
be used as you like. For example, they could be incorporated into logged
created for the logging event. This can be used in logging helpers so that
messages. For example::
the function name, filename and line number recorded are not the information
for the helper function/method, but rather its caller. The name of this
parameter mirrors the equivalent one in the :mod:`warnings` module.
The fourth keyword argument is *extra* which can be used to pass a
dictionary which is used to populate the __dict__ of the :class:`LogRecord`
created for the logging event with user-defined attributes. These custom
attributes can then be used as you like. For example, they could be
incorporated into logged messages. For example::
FORMAT = '
%(
asctime
)-
15
s
%(
clientip
)
s
%(
user
)-
8
s
%(
message
)
s
'
FORMAT = '
%(
asctime
)-
15
s
%(
clientip
)
s
%(
user
)-
8
s
%(
message
)
s
'
logging.basicConfig(format=FORMAT)
logging.basicConfig(format=FORMAT)
...
@@ -213,9 +221,9 @@ is the module's name in the Python package namespace.
...
@@ -213,9 +221,9 @@ is the module's name in the Python package namespace.
If you choose to use these attributes in logged messages, you need to exercise
If you choose to use these attributes in logged messages, you need to exercise
some care. In the above example, for instance, the :class:`Formatter` has been
some care. In the above example, for instance, the :class:`Formatter` has been
set up with a format string which expects '
clientip
' and '
user
' in the attribute
set up with a format string which expects '
clientip
' and '
user
' in the attribute
dictionary of the
LogRecord. If these are missing, the message will not be
dictionary of the
:class:`LogRecord`. If these are missing, the message will
logged because a string formatting exception will occur. So in this case, you
not be logged because a string formatting exception will occur. So in this case,
always need to pass the *extra* dictionary with these keys.
you
always need to pass the *extra* dictionary with these keys.
While this might be annoying, this feature is intended for use in specialized
While this might be annoying, this feature is intended for use in specialized
circumstances, such as multi-threaded servers where the same code executes in
circumstances, such as multi-threaded servers where the same code executes in
...
@@ -230,6 +238,9 @@ is the module's name in the Python package namespace.
...
@@ -230,6 +238,9 @@ is the module's name in the Python package namespace.
.. versionchanged:: 3.5
.. versionchanged:: 3.5
The *exc_info* parameter can now accept exception instances.
The *exc_info* parameter can now accept exception instances.
.. versionadded:: 3.8
The *stacklevel* parameter was added.
.. method:: Logger.info(msg, *args, **kwargs)
.. method:: Logger.info(msg, *args, **kwargs)
...
@@ -300,12 +311,19 @@ is the module's name in the Python package namespace.
...
@@ -300,12 +311,19 @@ is the module's name in the Python package namespace.
Removes
the
specified
handler
*
hdlr
*
from
this
logger
.
Removes
the
specified
handler
*
hdlr
*
from
this
logger
.
..
method
::
Logger
.
findCaller
(
stack_info
=
False
)
..
method
::
Logger
.
findCaller
(
stack_info
=
False
,
stacklevel
=
1
)
Finds
the
caller
's source filename and line number. Returns the filename, line
Finds
the
caller
's source filename and line number. Returns the filename, line
number, function name and stack information as a 4-element tuple. The stack
number, function name and stack information as a 4-element tuple. The stack
information is returned as ``None`` unless *stack_info* is ``True``.
information is returned as ``None`` unless *stack_info* is ``True``.
The *stacklevel* parameter is passed from code calling the :meth:`debug`
and other APIs. If greater than 1, the excess is used to skip stack frames
before determining the values to be returned. This will generally be useful
when calling logging APIs from helper/wrapper code, so that the information
in the event log refers not to the helper/wrapper code, but to the code that
calls it.
.. method:: Logger.handle(record)
.. method:: Logger.handle(record)
...
@@ -646,9 +664,9 @@ sophisticated criteria than levels, they get to see every record which is
...
@@ -646,9 +664,9 @@ sophisticated criteria than levels, they get to see every record which is
processed
by
the
handler
or
logger
they
're attached to: this can be useful if
processed
by
the
handler
or
logger
they
're attached to: this can be useful if
you want to do things like counting how many records were processed by a
you want to do things like counting how many records were processed by a
particular logger or handler, or adding, changing or removing attributes in
particular logger or handler, or adding, changing or removing attributes in
the
LogRecord being processed. Obviously changing the LogRecord needs to be
the
:class:`LogRecord` being processed. Obviously changing the LogRecord needs
done with some care, but it does allow the injection of contextual information
to be done with some care, but it does allow the injection of contextual
into logs (see :ref:`filters-contextual`).
in
formation in
to logs (see :ref:`filters-contextual`).
.. _log-record:
.. _log-record:
...
@@ -702,13 +720,13 @@ wire).
...
@@ -702,13 +720,13 @@ wire).
be used.
be used.
.. versionchanged:: 3.2
.. versionchanged:: 3.2
The creation of a
``LogRecord`
` has been made more configurable by
The creation of a
:class:`LogRecord
` has been made more configurable by
providing a factory which is used to create the record. The factory can be
providing a factory which is used to create the record. The factory can be
set using :func:`getLogRecordFactory` and :func:`setLogRecordFactory`
set using :func:`getLogRecordFactory` and :func:`setLogRecordFactory`
(see this for the factory'
s
signature
).
(see this for the factory'
s
signature
).
This
functionality
can
be
used
to
inject
your
own
values
into
a
This
functionality
can
be
used
to
inject
your
own
values
into
a
LogRecord
at
creation
time
.
You
can
use
the
following
pattern
::
:
class
:`
LogRecord
`
at
creation
time
.
You
can
use
the
following
pattern
::
old_factory
=
logging
.
getLogRecordFactory
()
old_factory
=
logging
.
getLogRecordFactory
()
...
...
Lib/logging/__init__.py
Dosyayı görüntüle @
dde9fdbe
...
@@ -1397,7 +1397,7 @@ class Logger(Filterer):
...
@@ -1397,7 +1397,7 @@ class Logger(Filterer):
if
self
.
isEnabledFor
(
level
):
if
self
.
isEnabledFor
(
level
):
self
.
_log
(
level
,
msg
,
args
,
**
kwargs
)
self
.
_log
(
level
,
msg
,
args
,
**
kwargs
)
def
findCaller
(
self
,
stack_info
=
False
):
def
findCaller
(
self
,
stack_info
=
False
,
stacklevel
=
1
):
"""
"""
Find the stack frame of the caller so that we can note the source
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
file name, line number and function name.
...
@@ -1407,6 +1407,12 @@ class Logger(Filterer):
...
@@ -1407,6 +1407,12 @@ class Logger(Filterer):
#IronPython isn't run with -X:Frames.
#IronPython isn't run with -X:Frames.
if
f
is
not
None
:
if
f
is
not
None
:
f
=
f
.
f_back
f
=
f
.
f_back
orig_f
=
f
while
f
and
stacklevel
>
1
:
f
=
f
.
f_back
stacklevel
-=
1
if
not
f
:
f
=
orig_f
rv
=
"(unknown file)"
,
0
,
"(unknown function)"
,
None
rv
=
"(unknown file)"
,
0
,
"(unknown function)"
,
None
while
hasattr
(
f
,
"f_code"
):
while
hasattr
(
f
,
"f_code"
):
co
=
f
.
f_code
co
=
f
.
f_code
...
@@ -1442,7 +1448,8 @@ class Logger(Filterer):
...
@@ -1442,7 +1448,8 @@ class Logger(Filterer):
rv
.
__dict__
[
key
]
=
extra
[
key
]
rv
.
__dict__
[
key
]
=
extra
[
key
]
return
rv
return
rv
def
_log
(
self
,
level
,
msg
,
args
,
exc_info
=
None
,
extra
=
None
,
stack_info
=
False
):
def
_log
(
self
,
level
,
msg
,
args
,
exc_info
=
None
,
extra
=
None
,
stack_info
=
False
,
stacklevel
=
1
):
"""
"""
Low-level logging routine which creates a LogRecord and then calls
Low-level logging routine which creates a LogRecord and then calls
all the handlers of this logger to handle the record.
all the handlers of this logger to handle the record.
...
@@ -1453,7 +1460,7 @@ class Logger(Filterer):
...
@@ -1453,7 +1460,7 @@ class Logger(Filterer):
#exception on some versions of IronPython. We trap it here so that
#exception on some versions of IronPython. We trap it here so that
#IronPython can use logging.
#IronPython can use logging.
try
:
try
:
fn
,
lno
,
func
,
sinfo
=
self
.
findCaller
(
stack_info
)
fn
,
lno
,
func
,
sinfo
=
self
.
findCaller
(
stack_info
,
stacklevel
)
except
ValueError
:
# pragma: no cover
except
ValueError
:
# pragma: no cover
fn
,
lno
,
func
=
"(unknown file)"
,
0
,
"(unknown function)"
fn
,
lno
,
func
=
"(unknown file)"
,
0
,
"(unknown function)"
else
:
# pragma: no cover
else
:
# pragma: no cover
...
...
Lib/test/test_logging.py
Dosyayı görüntüle @
dde9fdbe
...
@@ -4057,6 +4057,37 @@ class LoggerTest(BaseTest):
...
@@ -4057,6 +4057,37 @@ class LoggerTest(BaseTest):
self
.
assertEqual
(
len
(
called
),
1
)
self
.
assertEqual
(
len
(
called
),
1
)
self
.
assertEqual
(
'Stack (most recent call last):
\n
'
,
called
[
0
])
self
.
assertEqual
(
'Stack (most recent call last):
\n
'
,
called
[
0
])
def
test_find_caller_with_stacklevel
(
self
):
the_level
=
1
def
innermost
():
self
.
logger
.
warning
(
'test'
,
stacklevel
=
the_level
)
def
inner
():
innermost
()
def
outer
():
inner
()
records
=
self
.
recording
.
records
outer
()
self
.
assertEqual
(
records
[
-
1
]
.
funcName
,
'innermost'
)
lineno
=
records
[
-
1
]
.
lineno
the_level
+=
1
outer
()
self
.
assertEqual
(
records
[
-
1
]
.
funcName
,
'inner'
)
self
.
assertGreater
(
records
[
-
1
]
.
lineno
,
lineno
)
lineno
=
records
[
-
1
]
.
lineno
the_level
+=
1
outer
()
self
.
assertEqual
(
records
[
-
1
]
.
funcName
,
'outer'
)
self
.
assertGreater
(
records
[
-
1
]
.
lineno
,
lineno
)
lineno
=
records
[
-
1
]
.
lineno
the_level
+=
1
outer
()
self
.
assertEqual
(
records
[
-
1
]
.
funcName
,
'test_find_caller_with_stacklevel'
)
self
.
assertGreater
(
records
[
-
1
]
.
lineno
,
lineno
)
def
test_make_record_with_extra_overwrite
(
self
):
def
test_make_record_with_extra_overwrite
(
self
):
name
=
'my record'
name
=
'my record'
level
=
13
level
=
13
...
...
Misc/NEWS.d/next/Library/2018-06-05-12-43-25.bpo-33165.9TIsVf.rst
0 → 100644
Dosyayı görüntüle @
dde9fdbe
Added a stacklevel parameter to logging calls to allow use of wrapper/helper
functions for logging APIs.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment