Skip to content

Commit

Permalink
Fix Loguru Instrumentation for v0.7.0 (#798)
Browse files Browse the repository at this point in the history
* Add autosignature implementation

* Fix loguru with auto-signature

* [Mega-Linter] Apply linters fixes

* Fix tests for Py2

* [Mega-Linter] Apply linters fixes

* Bump tests

* Remove unwrap from signature utils

* Fix arg unpacking

* Remove unwrap arg from bind_args

* Fix linter errors

---------

Co-authored-by: TimPansino <TimPansino@users.noreply.github.com>
Co-authored-by: Lalleh Rafeei <lrafeei@newrelic.com>
  • Loading branch information
3 people authored Apr 12, 2023
1 parent 4d644c6 commit 153690f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 9 deletions.
31 changes: 31 additions & 0 deletions newrelic/common/signature.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2010 New Relic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from newrelic.packages import six

if six.PY3:
from inspect import Signature

def bind_args(func, args, kwargs):
"""Bind arguments and apply defaults to missing arugments for a callable."""
bound_args = Signature.from_callable(func).bind(*args, **kwargs)
bound_args.apply_defaults()
return bound_args.arguments

else:
from inspect import getcallargs

def bind_args(func, args, kwargs):
"""Bind arguments and apply defaults to missing arugments for a callable."""
return getcallargs(func, *args, **kwargs)
20 changes: 11 additions & 9 deletions newrelic/hooks/logger_loguru.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@
from newrelic.api.application import application_instance
from newrelic.api.transaction import current_transaction, record_log_event
from newrelic.common.object_wrapper import wrap_function_wrapper
from newrelic.common.signature import bind_args
from newrelic.core.config import global_settings
from newrelic.hooks.logger_logging import add_nr_linking_metadata
from newrelic.packages import six

_logger = logging.getLogger(__name__)
_logger = logging.getLogger(__name__)
is_pypy = hasattr(sys, "pypy_version_info")


def loguru_version():
from loguru import __version__

return tuple(int(x) for x in __version__.split("."))


Expand Down Expand Up @@ -54,7 +57,7 @@ def _nr_log_forwarder(message_instance):
if application and application.enabled:
application.record_custom_metric("Logging/lines", {"count": 1})
application.record_custom_metric("Logging/lines/%s" % level_name, {"count": 1})

if settings.application_logging.forwarding and settings.application_logging.forwarding.enabled:
try:
record_log_event(message, level_name, int(record["time"].timestamp()))
Expand All @@ -64,14 +67,13 @@ def _nr_log_forwarder(message_instance):

ALLOWED_LOGURU_OPTIONS_LENGTHS = frozenset((8, 9))

def bind_log(level_id, static_level_no, from_decorator, options, message, args, kwargs):
assert len(options) in ALLOWED_LOGURU_OPTIONS_LENGTHS # Assert the options signature we expect
return level_id, static_level_no, from_decorator, list(options), message, args, kwargs


def wrap_log(wrapped, instance, args, kwargs):
try:
level_id, static_level_no, from_decorator, options, message, subargs, subkwargs = bind_log(*args, **kwargs)
bound_args = bind_args(wrapped, args, kwargs)
options = bound_args["options"] = list(bound_args["options"])
assert len(options) in ALLOWED_LOGURU_OPTIONS_LENGTHS # Assert the options signature we expect

options[-2] = nr_log_patcher(options[-2])
# Loguru looks into the stack trace to find the caller's module and function names.
# options[1] tells loguru how far up to look in the stack trace to find the caller.
Expand All @@ -87,14 +89,14 @@ def wrap_log(wrapped, instance, args, kwargs):
_logger.debug("Exception in loguru handling: %s" % str(e))
return wrapped(*args, **kwargs)
else:
return wrapped(level_id, static_level_no, from_decorator, options, message, subargs, subkwargs)
return wrapped(**bound_args)


def nr_log_patcher(original_patcher=None):
def _nr_log_patcher(record):
if original_patcher:
record = original_patcher(record)

transaction = current_transaction()

if transaction:
Expand Down
31 changes: 31 additions & 0 deletions tests/agent_unittests/test_signature.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2010 New Relic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest

from newrelic.common.signature import bind_args


@pytest.mark.parametrize(
"func,args,kwargs,expected",
[
(lambda x, y: None, (1,), {"y": 2}, {"x": 1, "y": 2}),
(lambda x=1, y=2: None, (1,), {"y": 2}, {"x": 1, "y": 2}),
(lambda x=1: None, (), {}, {"x": 1}),
],
ids=("posargs", "kwargs", "defaults"),
)
def test_signature_binding(func, args, kwargs, expected):
bound_args = bind_args(func, args, kwargs)
assert bound_args == expected

0 comments on commit 153690f

Please sign in to comment.