Skip to content

Commit 1689445

Browse files
authored
Merge pull request #5059 from StackStorm/hotfix/python3-logging-filename
Fixed python 3 incompatibility in logging API implemenation of findCaller (v3.3 cherry pick)
2 parents e5bce50 + 10d3ccf commit 1689445

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ Fixed
107107
where the ``find_caller()`` function introduced some new variables. (bug fix) #4923
108108

109109
Contributed by @Dahfizz9897
110+
* Fixed another logging compatibility issue with the ``logging`` API in Python 3.
111+
The return from the ``logging.findCaller()`` implementation now expects a 4-element
112+
tuple. Also, in Python 3 there are new arguments that are passed in and needs to be
113+
acted upon, specificall ``stack_info`` that determines the new 4th element in the returned
114+
tuple. (bug fix) #5057
115+
116+
Contributed by Nick Maludy (@nmaludy Encore Technologies)
110117

111118
Removed
112119
~~~~~~~

st2common/st2common/log.py

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from __future__ import absolute_import
1717

18+
import io
1819
import os
1920
import sys
2021
import logging
@@ -69,25 +70,64 @@
6970
_srcfile = get_normalized_file_path(__file__)
7071

7172

72-
def find_caller(*args, **kwargs):
73+
def find_caller(stack_info=False, stacklevel=1):
7374
"""
7475
Find the stack frame of the caller so that we can note the source file name, line number and
7576
function name.
7677
7778
Note: This is based on logging/__init__.py:findCaller and modified so it takes into account
78-
this file - https://hg.python.org/cpython/file/2.7/Lib/logging/__init__.py#l1233
79+
this file:
80+
https://github.com/python/cpython/blob/2.7/Lib/logging/__init__.py#L1240-L1259
81+
82+
The Python 3.x implementation adds in a new argument `stack_info` and `stacklevel`
83+
and expects a 4-element tuple to be returned, rather than a 3-element tuple in
84+
the python 2 implementation.
85+
We derived our implementation from the Python 3.9 source code here:
86+
https://github.com/python/cpython/blob/3.9/Lib/logging/__init__.py#L1502-L1536
87+
88+
We've made the appropriate changes so that we're python 2 and python 3 compatible depending
89+
on what runtine we're working in.
7990
"""
80-
rv = '(unknown file)', 0, '(unknown function)'
91+
if six.PY2:
92+
rv = '(unknown file)', 0, '(unknown function)'
93+
else:
94+
# python 3, has extra tuple element at the end for stack information
95+
rv = '(unknown file)', 0, '(unknown function)', None
8196

8297
try:
83-
f = logging.currentframe().f_back
98+
f = logging.currentframe()
99+
# On some versions of IronPython, currentframe() returns None if
100+
# IronPython isn't run with -X:Frames.
101+
if f is not None:
102+
f = f.f_back
103+
orig_f = f
104+
while f and stacklevel > 1:
105+
f = f.f_back
106+
stacklevel -= 1
107+
if not f:
108+
f = orig_f
109+
84110
while hasattr(f, 'f_code'):
85111
co = f.f_code
86112
filename = os.path.normcase(co.co_filename)
87113
if filename in (_srcfile, logging._srcfile): # This line is modified.
88114
f = f.f_back
89115
continue
90-
rv = (filename, f.f_lineno, co.co_name)
116+
117+
if six.PY2:
118+
rv = (filename, f.f_lineno, co.co_name)
119+
else:
120+
# python 3, new stack_info processing and extra tuple return value
121+
sinfo = None
122+
if stack_info:
123+
sio = io.StringIO()
124+
sio.write('Stack (most recent call last):\n')
125+
traceback.print_stack(f, file=sio)
126+
sinfo = sio.getvalue()
127+
if sinfo[-1] == '\n':
128+
sinfo = sinfo[:-1]
129+
sio.close()
130+
rv = (filename, f.f_lineno, co.co_name, sinfo)
91131
break
92132
except Exception:
93133
pass

0 commit comments

Comments
 (0)