Skip to content

fix(profiling): make sure lineno is always an int and funcname is never None #3099

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions ddtrace/profiling/collector/_traceback.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ cpdef traceback_to_frames(traceback, max_nframes):
if nframes < max_nframes:
frame = tb.tb_frame
code = frame.f_code
frames.insert(0, (code.co_filename, frame.f_lineno, code.co_name))
lineno = 0 if frame.f_lineno is None else frame.f_lineno
frames.insert(0, (code.co_filename, lineno, code.co_name))
nframes += 1
tb = tb.tb_next
return frames, nframes
Expand All @@ -30,6 +31,7 @@ cpdef pyframe_to_frames(frame, max_nframes):
nframes += 1
if len(frames) < max_nframes:
code = frame.f_code
frames.append((code.co_filename, frame.f_lineno, code.co_name))
lineno = 0 if frame.f_lineno is None else frame.f_lineno
frames.append((code.co_filename, lineno, code.co_name))
frame = frame.f_back
return frames, nframes
21 changes: 19 additions & 2 deletions ddtrace/profiling/collector/threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import attr

import ddtrace
from ddtrace.internal import compat
from ddtrace.internal import nogevent
from ddtrace.internal.utils import attr as attr_utils
Expand All @@ -19,6 +20,10 @@
from ddtrace.vendor import wrapt


if typing.TYPE_CHECKING:
from ddtrace.profiling import recorder as ddrecorder


@event.event_class
class LockEventBase(event.StackBasedEvent):
"""Base Lock event."""
Expand Down Expand Up @@ -62,7 +67,16 @@ def _current_thread():


class _ProfiledLock(wrapt.ObjectProxy):
def __init__(self, wrapped, recorder, tracer, max_nframes, capture_sampler, endpoint_collection_enabled):
def __init__(
self,
wrapped, # type: threading.Lock
recorder, # type: ddrecorder.Recorder
tracer, # type: ddtrace.Tracer
max_nframes, # type: int
capture_sampler, # type: collector.CaptureSampler
endpoint_collection_enabled, # type: bool
):
# type: (...) -> None
wrapt.ObjectProxy.__init__(self, wrapped)
self._self_recorder = recorder
self._self_tracer = tracer
Expand All @@ -71,7 +85,10 @@ def __init__(self, wrapped, recorder, tracer, max_nframes, capture_sampler, endp
self._self_endpoint_collection_enabled = endpoint_collection_enabled
frame = sys._getframe(2 if WRAPT_C_EXT else 3)
code = frame.f_code
self._self_name = "%s:%d" % (os.path.basename(code.co_filename), frame.f_lineno)
self._self_name = "%s:%d" % (
os.path.basename(code.co_filename),
0 if frame.f_lineno is None else frame.f_lineno,
)

def acquire(self, *args, **kwargs):
if not self._self_capture_sampler.capture():
Expand Down
2 changes: 1 addition & 1 deletion ddtrace/profiling/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
_T = typing.TypeVar("_T")

# (filename, line number, function name)
FrameType = typing.Tuple[str, int, typing.Optional[str]]
FrameType = typing.Tuple[str, int, str]
StackTraceType = typing.List[FrameType]


Expand Down
8 changes: 2 additions & 6 deletions ddtrace/profiling/exporter/pprof.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,16 @@ class _PprofConverter(object):
self,
filename: str,
lineno: int,
funcname: typing.Optional[str] = None,
funcname: str,
) -> pprof_LocationType:
try:
return self._locations[(filename, lineno, funcname)]
except KeyError:
if funcname is None:
real_funcname = "<unknown function>"
else:
real_funcname = funcname
location = pprof_pb2.Location( # type: ignore[attr-defined]
id=self._last_location_id.generate(),
line=[
pprof_pb2.Line( # type: ignore[attr-defined]
function_id=self._to_Function(filename, real_funcname).id,
function_id=self._to_Function(filename, funcname).id,
line=lineno,
),
],
Expand Down