Skip to content

Commit a81513d

Browse files
Fix loguru detection of module/function name (#604)
* Fix loguru detection of module/function name * Add regression test * Add PyPy wrapper to loguru depth Co-authored-by: Tim Pansino <[email protected]>
1 parent 9da52c3 commit a81513d

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

newrelic/hooks/logger_loguru.py

+12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import logging
16+
import sys
1617

1718
from newrelic.api.application import application_instance
1819
from newrelic.api.transaction import current_transaction, record_log_event
@@ -22,6 +23,7 @@
2223
from newrelic.packages import six
2324

2425
_logger = logging.getLogger(__name__)
26+
is_pypy = hasattr(sys, "pypy_version_info")
2527

2628
def loguru_version():
2729
from loguru import __version__
@@ -71,6 +73,16 @@ def wrap_log(wrapped, instance, args, kwargs):
7173
try:
7274
level_id, static_level_no, from_decorator, options, message, subargs, subkwargs = bind_log(*args, **kwargs)
7375
options[-2] = nr_log_patcher(options[-2])
76+
# Loguru looks into the stack trace to find the caller's module and function names.
77+
# options[1] tells loguru how far up to look in the stack trace to find the caller.
78+
# Because wrap_log is an extra call in the stack trace, loguru needs to look 1 level higher.
79+
if not is_pypy:
80+
options[1] += 1
81+
else:
82+
# PyPy inspection requires an additional frame of offset, as the wrapt internals seem to
83+
# add another frame on PyPy but not on CPython.
84+
options[1] += 2
85+
7486
except Exception as e:
7587
_logger.debug("Exception in loguru handling: %s" % str(e))
7688
return wrapped(*args, **kwargs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright 2010 New Relic, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
17+
from conftest import CaplogHandler
18+
19+
from newrelic.api.background_task import background_task
20+
from testing_support.fixtures import reset_core_stats_engine
21+
from testing_support.validators.validate_log_event_count import validate_log_event_count
22+
from testing_support.validators.validate_log_events import validate_log_events
23+
from testing_support.fixtures import override_application_settings
24+
25+
26+
27+
@pytest.fixture(scope="function")
28+
def filepath_logger():
29+
import loguru
30+
_logger = loguru.logger
31+
caplog = CaplogHandler()
32+
handler_id = _logger.add(caplog, level="WARNING", format="{file}:{function} - {message}")
33+
_logger.caplog = caplog
34+
yield _logger
35+
del caplog.records[:]
36+
_logger.remove(handler_id)
37+
38+
39+
@override_application_settings({
40+
"application_logging.local_decorating.enabled": False,
41+
})
42+
@reset_core_stats_engine()
43+
def test_filepath_inspection(filepath_logger):
44+
# Test for regression in stack inspection that caused log messages.
45+
# See https://github.com/newrelic/newrelic-python-agent/issues/603
46+
47+
@validate_log_events([{"message": "A", "level": "ERROR"}])
48+
@validate_log_event_count(1)
49+
@background_task()
50+
def test():
51+
filepath_logger.error("A")
52+
assert len(filepath_logger.caplog.records) == 1
53+
record = filepath_logger.caplog.records[0]
54+
assert record == "test_stack_inspection.py:test - A", record
55+
56+
test()

0 commit comments

Comments
 (0)