Skip to content
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
11 changes: 8 additions & 3 deletions dynatrace_extension/sdk/callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from typing import Callable, Dict, Optional, Tuple

from .activation import ActivationType
from .communication import Status, StatusValue
from .communication import Status, StatusValue, MultiStatus


class WrappedCallback:
Expand Down Expand Up @@ -60,8 +60,13 @@ def __call__(self):
start_time = timer()
failed = False
try:
self.callback(*self.callback_args, **self.callback_kwargs)
self.status = Status(StatusValue.OK)
ret = self.callback(*self.callback_args, **self.callback_kwargs)
if isinstance(ret, Status):
self.status = ret
elif isinstance(ret, MultiStatus):
self.status = ret.build()
else:
self.status = Status(StatusValue.OK)
except Exception as e:
failed = True
self.logger.exception(f"Error running callback {self}: {e!r}")
Expand Down
23 changes: 23 additions & 0 deletions dynatrace_extension/sdk/communication.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,29 @@ def is_error(self) -> bool:
return self.status not in (StatusValue.OK, StatusValue.EMPTY)


class MultiStatus:

def __init__(self):
self.statuses = []

def add_status(self, status: StatusValue, message):
self.statuses.append(Status(status, message))

def build(self) -> Status:
ret = Status(StatusValue.OK)
if len(self.statuses) == 0:
return ret

messages = []
for stored_status in self.statuses:
print(stored_status)
if stored_status.is_error():
ret.status = stored_status.status
messages.append(stored_status.message)
ret.message = "\n".join(messages)
return ret


class CommunicationClient(ABC):
"""
Abstract class for extension communication
Expand Down
6 changes: 4 additions & 2 deletions dynatrace_extension/sdk/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from .activation import ActivationConfig, ActivationType
from .callback import WrappedCallback
from .communication import CommunicationClient, DebugClient, HttpClient, Status, StatusValue
from .communication import CommunicationClient, DebugClient, HttpClient, Status, StatusValue, MultiStatus
from .event import Severity
from .metric import Metric, MetricType, SfmMetric, SummaryStat
from .runtime import RuntimeProperties
Expand Down Expand Up @@ -974,7 +974,9 @@ def _build_current_status(self):
if callback.status.is_error():
overall_status.status = callback.status.status
messages.append(f"{callback}: {callback.status.message}")

continue
if callback.status.message is not None and callback.status.message != "":
messages.append(f"{callback}: {callback.status.message}")
overall_status.message = "\n".join(messages)
return overall_status

Expand Down
69 changes: 66 additions & 3 deletions tests/sdk/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from dynatrace_extension import Extension
from dynatrace_extension.sdk.communication import DebugClient
from dynatrace_extension.sdk.extension import Status, StatusValue
from dynatrace_extension.sdk.extension import Status, StatusValue, MultiStatus


class TestStatus(unittest.TestCase):
Expand Down Expand Up @@ -52,7 +52,7 @@ def bad_method():
self.assertEqual(status.status, StatusValue.GENERIC_ERROR)
self.assertIn("something went wrong", status.message)

def test_mutiple_bad_status(self):
def test_multiple_bad_status(self):
ext = Extension()
ext.logger = MagicMock()
ext._running_in_sim = True
Expand All @@ -70,7 +70,7 @@ def bad_method_2():
ext.schedule(bad_method_1, timedelta(seconds=1))
ext.schedule(bad_method_2, timedelta(seconds=1))
ext._scheduler.run(blocking=False)
time.sleep(0.01)
time.sleep(1)

status = ext._build_current_status()
self.assertEqual(status.status, StatusValue.GENERIC_ERROR)
Expand All @@ -93,3 +93,66 @@ def callback():

self.assertTrue(extension._scheduled_callbacks[1].status.is_error())
self.assertIn("longer than the interval", extension._scheduled_callbacks[1].status.message)

def test_direct_status_return(self):
ext = Extension()
ext.logger = MagicMock()
ext._running_in_sim = True
ext._client = DebugClient("", "", MagicMock())
ext._is_fastcheck = False

def callback():
return Status(StatusValue.OK, "foo1")

ext.schedule(callback, timedelta(seconds=1))
ext._scheduler.run(blocking=False)
time.sleep(0.01)

status = ext._build_current_status()
self.assertEqual(status.status, StatusValue.OK)
self.assertIn("foo1", status.message)

def test_direct_statuses_return(self):

def callback():
return Status(StatusValue.OK, "foo1")

def custom_query():
return Status(StatusValue.EMPTY, "foo2")

ext = Extension()
ext.logger = MagicMock()
ext._running_in_sim = True
ext._client = DebugClient("", "", MagicMock())
ext._is_fastcheck = False

ext.schedule(callback, timedelta(seconds=1))
ext.schedule(custom_query, timedelta(seconds=1))
ext._scheduler.run(blocking=False)
time.sleep(0.01)

status = ext._build_current_status()
self.assertEqual(status.status, StatusValue.OK)
self.assertIn("foo1", status.message)
self.assertIn("foo2", status.message)

def test_multistatus(self):
ext = Extension()
ext.logger = MagicMock()
ext._running_in_sim = True
ext._client = DebugClient("", "", MagicMock())
ext._is_fastcheck = False

def callback():
ret = MultiStatus()
ret.add_status(StatusValue.OK, "foo1")
ret.add_status(StatusValue.UNKNOWN_ERROR, "foo2")
return ret

ext.schedule(callback, timedelta(seconds=1))
ext._scheduler.run(blocking=False)
time.sleep(1)

status = ext._build_current_status()
self.assertEqual(status.status, StatusValue.UNKNOWN_ERROR)
self.assertIn("foo1", status.message)