dt-extensions-sdk 1.7.1__py3-none-any.whl → 1.7.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dt_extensions_sdk-1.7.1.dist-info → dt_extensions_sdk-1.7.3.dist-info}/METADATA +1 -1
- {dt_extensions_sdk-1.7.1.dist-info → dt_extensions_sdk-1.7.3.dist-info}/RECORD +10 -10
- dynatrace_extension/__about__.py +1 -1
- dynatrace_extension/sdk/callback.py +4 -4
- dynatrace_extension/sdk/communication.py +1 -1
- dynatrace_extension/sdk/extension.py +19 -18
- dynatrace_extension/sdk/status.py +19 -15
- {dt_extensions_sdk-1.7.1.dist-info → dt_extensions_sdk-1.7.3.dist-info}/WHEEL +0 -0
- {dt_extensions_sdk-1.7.1.dist-info → dt_extensions_sdk-1.7.3.dist-info}/entry_points.txt +0 -0
- {dt_extensions_sdk-1.7.1.dist-info → dt_extensions_sdk-1.7.3.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dt-extensions-sdk
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.3
|
|
4
4
|
Project-URL: Documentation, https://github.com/dynatrace-extensions/dt-extensions-python-sdk#readme
|
|
5
5
|
Project-URL: Issues, https://github.com/dynatrace-extensions/dt-extensions-python-sdk/issues
|
|
6
6
|
Project-URL: Source, https://github.com/dynatrace-extensions/dt-extensions-python-sdk
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
dynatrace_extension/__about__.py,sha256
|
|
1
|
+
dynatrace_extension/__about__.py,sha256=-BvmT9sstUN3n3QmUgym0fwfILxaCrccJsuxxXpn5H0,110
|
|
2
2
|
dynatrace_extension/__init__.py,sha256=MJNJYCFWLEwPmBLoETWFZddyUCMDgZfKkRycmmGM_w4,806
|
|
3
3
|
dynatrace_extension/cli/__init__.py,sha256=HCboY_eJPoqjFmoPDsBL8Jk6aNvank8K7JpkVrgwzUM,123
|
|
4
4
|
dynatrace_extension/cli/main.py,sha256=OTjJ4XHJvvYXj10a7WFFHVNnkyECPg1ClW6Os8piN8k,20168
|
|
@@ -17,22 +17,22 @@ dynatrace_extension/cli/create/extension_template/extension_name/__init__.py.tem
|
|
|
17
17
|
dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template,sha256=cS79GVxJB-V-gocu4ZOjmZ54HXJNg89eXdLf89zDHJQ,1249
|
|
18
18
|
dynatrace_extension/sdk/__init__.py,sha256=RsqQ1heGyCmSK3fhuEKAcxQIRCg4gEK0-eSkIehL5Nc,86
|
|
19
19
|
dynatrace_extension/sdk/activation.py,sha256=KIoPWMZs3tKiMG8XhCfeNgRlz2vxDKcAASgSACcEfIQ,1456
|
|
20
|
-
dynatrace_extension/sdk/callback.py,sha256=
|
|
21
|
-
dynatrace_extension/sdk/communication.py,sha256
|
|
20
|
+
dynatrace_extension/sdk/callback.py,sha256=NW63fQBh-BeN-zfAeDY94wpSBoBHRsR3VLJCvxJPiaw,6703
|
|
21
|
+
dynatrace_extension/sdk/communication.py,sha256=uTSURmgSHit2N1hHUc3-yKmEBVMHi6hDBrdb1EaCAsE,18419
|
|
22
22
|
dynatrace_extension/sdk/event.py,sha256=J261imbFKpxfuAQ6Nfu3RRcsIQKKivy6fme1nww2g-8,388
|
|
23
|
-
dynatrace_extension/sdk/extension.py,sha256=
|
|
23
|
+
dynatrace_extension/sdk/extension.py,sha256=KZYVn5VDW19pfnqe6UnpzRVPYUasW8n8AYSvUYvvOUw,49723
|
|
24
24
|
dynatrace_extension/sdk/helper.py,sha256=m4gGHtIKYkfANC2MOGdxKUZlmH5tnZO6WTNqll27lyY,6476
|
|
25
25
|
dynatrace_extension/sdk/metric.py,sha256=-kq7JWpk7UGvcjqafTt-o6k4urwhsGVXmnuQg7Sf9PQ,3622
|
|
26
26
|
dynatrace_extension/sdk/runtime.py,sha256=7bC4gUJsVSHuL_E7r2EWrne95nm1BjZiMGkyNqA7ZCU,2796
|
|
27
27
|
dynatrace_extension/sdk/snapshot.py,sha256=LnWVCtCK4NIEV3_kX-ly_LGHpNBSeErtsxCI1PH3L28,7521
|
|
28
|
-
dynatrace_extension/sdk/status.py,sha256=
|
|
28
|
+
dynatrace_extension/sdk/status.py,sha256=fE0qCGaanV7Ss1144p-dLX9uJMKIb0Rs6A0pLZLPlrI,8599
|
|
29
29
|
dynatrace_extension/sdk/throttled_logger.py,sha256=JXDiHh8syl8R0gJ-wfxmmBqvGCBMQX4pxPkxscaCsXo,3292
|
|
30
30
|
dynatrace_extension/sdk/vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
31
|
dynatrace_extension/sdk/vendor/mureq/LICENSE,sha256=8AVcgZgiT_mvK1fOofXtRRr2f1dRXS_K21NuxQgP4VM,671
|
|
32
32
|
dynatrace_extension/sdk/vendor/mureq/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
dynatrace_extension/sdk/vendor/mureq/mureq.py,sha256=znF4mvzk5L03CLNozRz8UpK-fMijmSkObDFwlbhwLUg,14656
|
|
34
|
-
dt_extensions_sdk-1.7.
|
|
35
|
-
dt_extensions_sdk-1.7.
|
|
36
|
-
dt_extensions_sdk-1.7.
|
|
37
|
-
dt_extensions_sdk-1.7.
|
|
38
|
-
dt_extensions_sdk-1.7.
|
|
34
|
+
dt_extensions_sdk-1.7.3.dist-info/METADATA,sha256=irv3Te4njH0dWl4Yl-KyNN--ErS4PP7-xrghjwbtoqo,2721
|
|
35
|
+
dt_extensions_sdk-1.7.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
36
|
+
dt_extensions_sdk-1.7.3.dist-info/entry_points.txt,sha256=pweyOCgENGHjOlT6_kXYaBPOrE3p18K0UettqnNlnoE,55
|
|
37
|
+
dt_extensions_sdk-1.7.3.dist-info/licenses/LICENSE.txt,sha256=3Zihv0lOVYHNfDkJC-tUAU6euP9r2NexsDW4w-zqgVk,1078
|
|
38
|
+
dt_extensions_sdk-1.7.3.dist-info/RECORD,,
|
dynatrace_extension/__about__.py
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
import random
|
|
7
|
+
import time
|
|
7
8
|
from collections.abc import Callable
|
|
8
9
|
from datetime import datetime, timedelta
|
|
9
10
|
from timeit import default_timer as timer
|
|
@@ -39,6 +40,7 @@ class WrappedCallback:
|
|
|
39
40
|
self.duration = 0 # global counter
|
|
40
41
|
self.duration_interval_total = 0 # counter per interval = 1 min by default
|
|
41
42
|
self.cluster_time_diff = 0
|
|
43
|
+
self.start_timestamp_monotonic = time.monotonic()
|
|
42
44
|
self.start_timestamp = self.get_current_time_with_cluster_diff()
|
|
43
45
|
self.running_in_sim = running_in_sim
|
|
44
46
|
self.activation_type = activation_type
|
|
@@ -147,8 +149,6 @@ class WrappedCallback:
|
|
|
147
149
|
"""
|
|
148
150
|
Get the timestamp for the next execution of the callback
|
|
149
151
|
This is done using execution total, the interval and the start timestamp
|
|
150
|
-
:return:
|
|
152
|
+
:return: float
|
|
151
153
|
"""
|
|
152
|
-
return (
|
|
153
|
-
self.start_timestamp + timedelta(seconds=self.interval.total_seconds() * (self.iterations or 1))
|
|
154
|
-
).timestamp()
|
|
154
|
+
return self.start_timestamp_monotonic + self.interval.total_seconds() * (self.iterations or 1)
|
|
@@ -343,7 +343,7 @@ class DebugClient(CommunicationClient):
|
|
|
343
343
|
def get_feature_sets(self) -> dict[str, list[str]]:
|
|
344
344
|
# This is only called from dt-sdk run, where PyYaml is installed because of dt-cli
|
|
345
345
|
# Do NOT move this to the top of the file
|
|
346
|
-
import yaml #
|
|
346
|
+
import yaml # noqa: PLC0415
|
|
347
347
|
|
|
348
348
|
# Grab the feature sets from the extension.yaml file
|
|
349
349
|
extension_yaml = yaml.safe_load(self.extension_config)
|
|
@@ -28,10 +28,11 @@ from .snapshot import Snapshot
|
|
|
28
28
|
from .status import EndpointStatuses, EndpointStatusesMap, IgnoreStatus, Status, StatusValue
|
|
29
29
|
from .throttled_logger import StrictThrottledHandler, ThrottledHandler
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
# Intervals defined in seconds for internal callbacks
|
|
32
|
+
HEARTBEAT_INTERVAL = 50
|
|
33
|
+
METRIC_SENDING_INTERVAL = 30
|
|
34
|
+
SFM_METRIC_SENDING_INTERVAL = 60
|
|
35
|
+
TIME_DIFF_INTERVAL = 60
|
|
35
36
|
|
|
36
37
|
CALLBACKS_THREAD_POOL_SIZE = 100
|
|
37
38
|
INTERNAL_THREAD_POOL_SIZE = 20
|
|
@@ -180,11 +181,11 @@ class Extension:
|
|
|
180
181
|
"""
|
|
181
182
|
|
|
182
183
|
_instance: ClassVar = None
|
|
183
|
-
schedule_decorators: ClassVar = []
|
|
184
|
+
schedule_decorators: ClassVar[list[tuple[Callable, timedelta | int, tuple | None, ActivationType | None]]] = []
|
|
184
185
|
|
|
185
186
|
def __new__(cls, *args, **kwargs): # noqa: ARG004
|
|
186
187
|
if Extension._instance is None:
|
|
187
|
-
Extension._instance = super(
|
|
188
|
+
Extension._instance = super().__new__(cls)
|
|
188
189
|
return Extension._instance
|
|
189
190
|
|
|
190
191
|
def __init__(self, name: str = "") -> None:
|
|
@@ -240,15 +241,15 @@ class Extension:
|
|
|
240
241
|
self._running_callbacks: dict[int, WrappedCallback] = {}
|
|
241
242
|
self._running_callbacks_lock: Lock = Lock()
|
|
242
243
|
|
|
243
|
-
self._scheduler = sched.scheduler(time.
|
|
244
|
+
self._scheduler = sched.scheduler(time.monotonic, time.sleep)
|
|
244
245
|
|
|
245
246
|
# Timestamps for scheduling of internal callbacks
|
|
246
|
-
self._next_internal_callbacks_timestamps: dict[str,
|
|
247
|
-
"timediff":
|
|
248
|
-
"heartbeat":
|
|
249
|
-
"metrics":
|
|
250
|
-
"events":
|
|
251
|
-
"sfm_metrics":
|
|
247
|
+
self._next_internal_callbacks_timestamps: dict[str, float] = {
|
|
248
|
+
"timediff": time.monotonic() + TIME_DIFF_INTERVAL,
|
|
249
|
+
"heartbeat": time.monotonic() + HEARTBEAT_INTERVAL,
|
|
250
|
+
"metrics": time.monotonic() + METRIC_SENDING_INTERVAL,
|
|
251
|
+
"events": time.monotonic() + METRIC_SENDING_INTERVAL,
|
|
252
|
+
"sfm_metrics": time.monotonic() + SFM_METRIC_SENDING_INTERVAL,
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
# Executors for the callbacks and internal methods
|
|
@@ -412,7 +413,7 @@ class Extension:
|
|
|
412
413
|
else:
|
|
413
414
|
self._schedule_callback(callback)
|
|
414
415
|
|
|
415
|
-
def query(self):
|
|
416
|
+
def query(self) -> Any:
|
|
416
417
|
"""Callback to be executed every minute by default.
|
|
417
418
|
|
|
418
419
|
Optional method that can be implemented by subclasses.
|
|
@@ -683,7 +684,7 @@ class Extension:
|
|
|
683
684
|
msg = f"Event type must be a DtEventType enum value, got: {value}"
|
|
684
685
|
raise ValueError(msg)
|
|
685
686
|
if key == "properties":
|
|
686
|
-
for prop_key, prop_val in
|
|
687
|
+
for prop_key, prop_val in value.items():
|
|
687
688
|
if not isinstance(prop_key, str) or not isinstance(prop_val, str):
|
|
688
689
|
msg = f'invalid "properties" member: {prop_key}: {prop_val}, required: "str": str'
|
|
689
690
|
raise ValueError(msg)
|
|
@@ -777,7 +778,7 @@ class Extension:
|
|
|
777
778
|
parser.add_argument("--secrets", required=False, default="secrets.json")
|
|
778
779
|
parser.add_argument("--no-print-metrics", required=False, action="store_true")
|
|
779
780
|
|
|
780
|
-
args,
|
|
781
|
+
args, _ = parser.parse_known_args()
|
|
781
782
|
self._is_fastcheck = args.fastcheck
|
|
782
783
|
if args.dsid is None:
|
|
783
784
|
# DEV mode
|
|
@@ -1169,10 +1170,10 @@ class Extension:
|
|
|
1169
1170
|
def _send_dt_event(self, event: dict[str, str | int | dict[str, str]]):
|
|
1170
1171
|
self._client.send_dt_event(event)
|
|
1171
1172
|
|
|
1172
|
-
def _get_and_set_next_internal_callback_timestamp(self, callback_name: str, interval:
|
|
1173
|
+
def _get_and_set_next_internal_callback_timestamp(self, callback_name: str, interval: float) -> float:
|
|
1173
1174
|
next_timestamp = self._next_internal_callbacks_timestamps[callback_name]
|
|
1174
1175
|
self._next_internal_callbacks_timestamps[callback_name] += interval
|
|
1175
|
-
return next_timestamp
|
|
1176
|
+
return next_timestamp
|
|
1176
1177
|
|
|
1177
1178
|
def get_version(self) -> str:
|
|
1178
1179
|
"""Return the extension version."""
|
|
@@ -114,6 +114,9 @@ class EndpointStatus:
|
|
|
114
114
|
def __eq__(self, other):
|
|
115
115
|
return isinstance(other, EndpointStatus) and self.__dict__ == other.__dict__
|
|
116
116
|
|
|
117
|
+
def __hash__(self):
|
|
118
|
+
return hash(tuple(sorted(self.__dict__.items())))
|
|
119
|
+
|
|
117
120
|
|
|
118
121
|
class EndpointStatuses:
|
|
119
122
|
def __init__(self, total_endpoints_number=None) -> None:
|
|
@@ -227,33 +230,34 @@ class EndpointStatusesMap:
|
|
|
227
230
|
with self._lock:
|
|
228
231
|
# Summarize all statuses
|
|
229
232
|
ok_count = 0
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
+
warning_count = 0
|
|
234
|
+
error_count = 0
|
|
235
|
+
messages_to_report = []
|
|
233
236
|
|
|
234
237
|
for ep_record in self._ep_records.values():
|
|
235
238
|
ep_status = ep_record.ep_status
|
|
236
|
-
if ep_status.status.is_warning():
|
|
237
|
-
has_warning_status = True
|
|
238
239
|
|
|
239
|
-
if ep_status.status.
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
if ep_status.status.is_warning():
|
|
241
|
+
warning_count += 1
|
|
242
|
+
messages_to_report.append(f"{ep_status.endpoint} - {ep_status.status.value} {ep_status.message}")
|
|
243
|
+
elif ep_status.status.is_error():
|
|
244
|
+
error_count += 1
|
|
245
|
+
messages_to_report.append(f"{ep_status.endpoint} - {ep_status.status.value} {ep_status.message}")
|
|
242
246
|
else:
|
|
243
247
|
ok_count += 1
|
|
244
248
|
|
|
249
|
+
status_msg = f"Endpoints OK: {ok_count} WARNING: {warning_count} ERROR: {error_count}"
|
|
250
|
+
|
|
245
251
|
# Early return if all OK
|
|
246
|
-
if
|
|
247
|
-
return Status(StatusValue.OK,
|
|
252
|
+
if error_count == 0 and warning_count == 0:
|
|
253
|
+
return Status(StatusValue.OK, status_msg)
|
|
248
254
|
|
|
249
255
|
# Build final status if some errors present
|
|
250
|
-
|
|
251
|
-
all_endpoints_faulty = ok_count == 0
|
|
256
|
+
status_msg += f" Unhealthy endpoints: {', '.join(messages_to_report)}"
|
|
252
257
|
|
|
253
|
-
if
|
|
258
|
+
if ok_count == 0 and warning_count == 0:
|
|
254
259
|
status_value = StatusValue.GENERIC_ERROR
|
|
255
260
|
else:
|
|
256
261
|
status_value = StatusValue.WARNING
|
|
257
262
|
|
|
258
|
-
|
|
259
|
-
return Status(status=status_value, message=message)
|
|
263
|
+
return Status(status=status_value, message=status_msg)
|
|
File without changes
|
|
File without changes
|
{dt_extensions_sdk-1.7.1.dist-info → dt_extensions_sdk-1.7.3.dist-info}/licenses/LICENSE.txt
RENAMED
|
File without changes
|