From 7e38c761b8f7308325fe5f2b7677e47c2d8298ec Mon Sep 17 00:00:00 2001 From: Nick Maludy Date: Wed, 14 Oct 2020 16:25:10 -0400 Subject: [PATCH 1/3] Fixed python 3 incompatibility in logging API implemenation of findCaller --- CHANGELOG.rst | 7 ++++++ st2common/st2common/log.py | 47 ++++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4730418276..8fd54b927b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -106,6 +106,13 @@ Fixed where the ``find_caller()`` function introduced some new variables. (bug fix) #4923 Contributed by @Dahfizz9897 +* Fixed another logging compatibility issue with the ``logging`` API in Python 3. + The return from the ``logging.findCaller()`` implementation now expects a 4-element + tuple. Also, in Python 3 there are new arguments that are passed in and needs to be + acted upon, specificall ``stack_info`` that determines the new 4th element in the returned + tuple. (bug fix) #5057 + + Contributed by Nick Maludy (@nmaludy Encore Technologies) Removed ~~~~~~~ diff --git a/st2common/st2common/log.py b/st2common/st2common/log.py index 5248ec8969..71146df79a 100644 --- a/st2common/st2common/log.py +++ b/st2common/st2common/log.py @@ -69,25 +69,62 @@ _srcfile = get_normalized_file_path(__file__) -def find_caller(*args, **kwargs): +def find_caller(stack_info=False, stacklevel=1): """ Find the stack frame of the caller so that we can note the source file name, line number and function name. Note: This is based on logging/__init__.py:findCaller and modified so it takes into account - this file - https://hg.python.org/cpython/file/2.7/Lib/logging/__init__.py#l1233 + this file: + https://github.com/python/cpython/blob/2.7/Lib/logging/__init__.py#L1240-L1259 + + The Python 3.x implementation adds in a new argument `stack_info` and `stacklevel` + and expects a 4-element tuple to be returned, rather than a 3-element tuple in + the python 2 implementation. + We derived our implementation from the Python 3.9 source code here: + https://github.com/python/cpython/blob/3.9/Lib/logging/__init__.py#L1376-L1404 + + We've made the appropriate changes so that we're python 2 and python 3 compatible depending + on what runtine we're working in. """ - rv = '(unknown file)', 0, '(unknown function)' + if six.PY2: + rv = '(unknown file)', 0, '(unknown function)' + else: # python 3, has extra tuple element at the end for stack information + rv = '(unknown file)', 0, '(unknown function)', None try: - f = logging.currentframe().f_back + f = logging.currentframe() + #On some versions of IronPython, currentframe() returns None if + #IronPython isn't run with -X:Frames. + if f is not None: + f = f.f_back + orig_f = f + while f and stacklevel > 1: + f = f.f_back + stacklevel -= 1 + if not f: + f = orig_f + while hasattr(f, 'f_code'): co = f.f_code filename = os.path.normcase(co.co_filename) if filename in (_srcfile, logging._srcfile): # This line is modified. f = f.f_back continue - rv = (filename, f.f_lineno, co.co_name) + + if six.PY2: + rv = (filename, f.f_lineno, co.co_name) + else: # python 3, new stack_info processing and extra tuple return value + sinfo = None + if stack_info: + sio = io.StringIO() + sio.write('Stack (most recent call last):\n') + traceback.print_stack(f, file=sio) + sinfo = sio.getvalue() + if sinfo[-1] == '\n': + sinfo = sinfo[:-1] + sio.close() + rv = (filename, f.f_lineno, co.co_name, sinfo) break except Exception: pass From b3dd45f9c80937a54793cb8c0b913615c3a7382c Mon Sep 17 00:00:00 2001 From: W Chan Date: Wed, 14 Oct 2020 22:39:37 +0000 Subject: [PATCH 2/3] Fix lint and flake8 issues with the logging code --- st2common/st2common/log.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/st2common/st2common/log.py b/st2common/st2common/log.py index 71146df79a..46767d5d6b 100644 --- a/st2common/st2common/log.py +++ b/st2common/st2common/log.py @@ -15,6 +15,7 @@ from __future__ import absolute_import +import io import os import sys import logging @@ -89,13 +90,14 @@ def find_caller(stack_info=False, stacklevel=1): """ if six.PY2: rv = '(unknown file)', 0, '(unknown function)' - else: # python 3, has extra tuple element at the end for stack information + else: + # python 3, has extra tuple element at the end for stack information rv = '(unknown file)', 0, '(unknown function)', None try: f = logging.currentframe() - #On some versions of IronPython, currentframe() returns None if - #IronPython isn't run with -X:Frames. + # On some versions of IronPython, currentframe() returns None if + # IronPython isn't run with -X:Frames. if f is not None: f = f.f_back orig_f = f @@ -114,7 +116,8 @@ def find_caller(stack_info=False, stacklevel=1): if six.PY2: rv = (filename, f.f_lineno, co.co_name) - else: # python 3, new stack_info processing and extra tuple return value + else: + # python 3, new stack_info processing and extra tuple return value sinfo = None if stack_info: sio = io.StringIO() From 10d3ccf510c476eba3216970f00fdc54ceca2213 Mon Sep 17 00:00:00 2001 From: Nick Maludy Date: Wed, 14 Oct 2020 20:59:39 -0400 Subject: [PATCH 3/3] Update st2common/st2common/log.py Co-authored-by: Jacob Floyd --- st2common/st2common/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st2common/st2common/log.py b/st2common/st2common/log.py index 46767d5d6b..5335af5f53 100644 --- a/st2common/st2common/log.py +++ b/st2common/st2common/log.py @@ -83,7 +83,7 @@ def find_caller(stack_info=False, stacklevel=1): and expects a 4-element tuple to be returned, rather than a 3-element tuple in the python 2 implementation. We derived our implementation from the Python 3.9 source code here: - https://github.com/python/cpython/blob/3.9/Lib/logging/__init__.py#L1376-L1404 + https://github.com/python/cpython/blob/3.9/Lib/logging/__init__.py#L1502-L1536 We've made the appropriate changes so that we're python 2 and python 3 compatible depending on what runtine we're working in.