Skip to content

Commit

Permalink
fix(profiling): get_frame_name only look at arguments (#1684)
Browse files Browse the repository at this point in the history
Looking for `self` and `cls` is not sufficient because they may have come from
an outer scope. Make sure to check that they are coming from the frame's
positional arguments.

Co-authored-by: Anton Pirker <anton.pirker@sentry.io>
  • Loading branch information
Zylphrex and antonpirker committed Oct 20, 2022
1 parent 29431f6 commit d2547ea
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
19 changes: 16 additions & 3 deletions sentry_sdk/profiler.py
Expand Up @@ -202,22 +202,35 @@ def get_frame_name(frame):
# in 3.11+, there is a frame.f_code.co_qualname that
# we should consider using instead where possible

f_code = frame.f_code
# co_name only contains the frame name. If the frame was a method,
# the class name will NOT be included.
name = frame.f_code.co_name
name = f_code.co_name

# if it was a method, we can get the class name by inspecting
# the f_locals for the `self` argument
try:
if "self" in frame.f_locals:
if (
# the co_varnames start with the frame's positional arguments
# and we expect the first to be `self` if its an instance method
f_code.co_varnames
and f_code.co_varnames[0] == "self"
and "self" in frame.f_locals
):
return "{}.{}".format(frame.f_locals["self"].__class__.__name__, name)
except AttributeError:
pass

# if it was a class method, (decorated with `@classmethod`)
# we can get the class name by inspecting the f_locals for the `cls` argument
try:
if "cls" in frame.f_locals:
if (
# the co_varnames start with the frame's positional arguments
# and we expect the first to be `cls` if its a class method
f_code.co_varnames
and f_code.co_varnames[0] == "cls"
and "cls" in frame.f_locals
):
return "{}.{}".format(frame.f_locals["cls"].__name__, name)
except AttributeError:
pass
Expand Down
25 changes: 25 additions & 0 deletions tests/test_profiler.py
Expand Up @@ -85,10 +85,25 @@ class GetFrame:
def instance_method(self):
return inspect.currentframe()

def instance_method_wrapped(self):
def wrapped():
self
return inspect.currentframe()

return wrapped

@classmethod
def class_method(cls):
return inspect.currentframe()

@classmethod
def class_method_wrapped(cls):
def wrapped():
cls
return inspect.currentframe()

return wrapped

@staticmethod
def static_method():
return inspect.currentframe()
Expand All @@ -112,11 +127,21 @@ def static_method():
"GetFrame.instance_method",
id="instance_method",
),
pytest.param(
GetFrame().instance_method_wrapped()(),
"wrapped",
id="instance_method_wrapped",
),
pytest.param(
GetFrame().class_method(),
"GetFrame.class_method",
id="class_method",
),
pytest.param(
GetFrame().class_method_wrapped()(),
"wrapped",
id="class_method_wrapped",
),
pytest.param(
GetFrame().static_method(),
"GetFrame.static_method",
Expand Down

0 comments on commit d2547ea

Please sign in to comment.