Skip to content
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

Add APPMAP_MAX_TIME #337

Merged
merged 3 commits into from
Jun 5, 2024
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
4 changes: 3 additions & 1 deletion _appmap/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ def describe_value(name, val, max_depth=5):
"object_id": id(val),
"value": display_string(val),
}
ret.update(_describe_schema(name, val, 0, max_depth))
if Env.current.display_params:
ret.update(_describe_schema(name, val, 0, max_depth))

if any(_is_list_or_dict(type(val))):
ret["size"] = len(val)

Expand Down
5 changes: 3 additions & 2 deletions _appmap/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from . import event
from .env import Env
from .event import CallEvent
from .recorder import Recorder, AppMapTooManyEvents
from .recorder import Recorder, AppMapLimitExceeded
from .utils import appmap_tls

logger = Env.current.getLogger(__name__)
Expand Down Expand Up @@ -90,6 +90,7 @@ def call_instrumented(f, instance, args, kwargs):
call_event_id = call_event.id
start_time = time.time()
try:
Recorder.check_time(start_time)
ret = f.fn(*args, **kwargs)
elapsed_time = time.time() - start_time

Expand All @@ -98,7 +99,7 @@ def call_instrumented(f, instance, args, kwargs):
)
Recorder.add_event(return_event)
return ret
except AppMapTooManyEvents:
except AppMapLimitExceeded:
raise
except Exception: # noqa: E722
elapsed_time = time.time() - start_time
Expand Down
26 changes: 24 additions & 2 deletions _appmap/recorder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import threading
import time
import traceback
from abc import ABC, abstractmethod

Expand All @@ -17,11 +18,23 @@
if _MAX_EVENTS is not None:
_MAX_EVENTS = int(_MAX_EVENTS)

_MAX_TIME = Env.current.get("APPMAP_MAX_TIME")
if _MAX_TIME is not None:
_MAX_TIME = int(_MAX_TIME)

class AppMapTooManyEvents(RuntimeError):

class AppMapLimitExceeded(RuntimeError):
"""Class of events thrown when some limit has been exceeded"""


class AppMapTooManyEvents(AppMapLimitExceeded):
"""Thrown when a recorder has more than APPMAP_MAX_EVENTS"""


class AppMapSessionTooLong(AppMapLimitExceeded):
"""Throw when an individual recording session has exceeded APPMAP_MAX_TIME"""


class Recorder(ABC):
"""
A base class for Recorders.
Expand Down Expand Up @@ -97,6 +110,13 @@ def start_recording(cls):
def stop_recording(cls):
return cls.get_current()._stop_recording() # pylint: disable=protected-access

@classmethod
def check_time(cls, event_time):
if _MAX_TIME is None:
return
if event_time - cls.get_current()._start_time > _MAX_TIME:
raise AppMapSessionTooLong(f"Session exceeded {_MAX_TIME} seconds")

@classmethod
def add_event(cls, event):
"""
Expand Down Expand Up @@ -124,6 +144,7 @@ def __init__(self, enabled=False):
self._events = []
self._enabled = enabled
self.start_tb = None
self._start_time = None

@abstractmethod
def _start_recording(self):
Expand All @@ -134,6 +155,7 @@ def _start_recording(self):
raise RuntimeError("Recording already in progress")
self.start_tb = traceback.extract_stack()
self._enabled = True
self._start_time = time.time()

@abstractmethod
def _stop_recording(self):
Expand All @@ -150,7 +172,7 @@ def _add_event(self, event):
self._events.append(event)
if _MAX_EVENTS is not None and len(self._events) > _MAX_EVENTS:
Recorder._aborting = True
raise AppMapTooManyEvents()
raise AppMapTooManyEvents(f"Session exceeded {_MAX_EVENTS} events")

@staticmethod
def _initialize():
Expand Down
13 changes: 6 additions & 7 deletions vendor/_appmap/wrapt/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,11 @@ def __reduce__(self):
raise NotImplementedError(
'object proxy must define __reduce_ex__()')

# Return the qualname of the wrapped function instead of a tuple. This allows an instance of
# subclasses to be pickled as the function it wraps. This seems to be adequate for generating
# AppMaps.
def __reduce_ex__(self, protocol):
raise NotImplementedError(
'object proxy must define __reduce_ex__()')
return self.__wrapped__.__qualname__

class CallableObjectProxy(ObjectProxy):

Expand Down Expand Up @@ -740,12 +742,9 @@ class FunctionWrapper(_FunctionWrapperBase):
# new FunctionWrapper will be created. If it doesn't, then __reduce_ex__ can simply return a
# string, which would cause deepcopy to return the original FunctionWrapper.
#
# Update: We'll return the qualname of the wrapped function instead of a tuple allows a
# FunctionWrapper to be pickled (as the function it wraps). This seems to be adequate for
# generating AppMaps, so go with that.

def __reduce_ex__(self, protocol):
return self.__wrapped__.__qualname__
# def __reduce_ex__(self, protocol):
# return self.__wrapped__.__qualname__

# return FunctionWrapper, (
# self.__wrapped__,
Expand Down
Loading