dt-extensions-sdk 1.1.14__py3-none-any.whl → 1.1.16__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.1.14.dist-info → dt_extensions_sdk-1.1.16.dist-info}/METADATA +1 -1
- {dt_extensions_sdk-1.1.14.dist-info → dt_extensions_sdk-1.1.16.dist-info}/RECORD +10 -10
- dynatrace_extension/__about__.py +1 -1
- dynatrace_extension/cli/create/extension_template/extension/extension.yaml.template +3 -3
- dynatrace_extension/cli/create/extension_template/setup.py.template +17 -1
- dynatrace_extension/sdk/communication.py +64 -14
- dynatrace_extension/sdk/extension.py +16 -13
- {dt_extensions_sdk-1.1.14.dist-info → dt_extensions_sdk-1.1.16.dist-info}/WHEEL +0 -0
- {dt_extensions_sdk-1.1.14.dist-info → dt_extensions_sdk-1.1.16.dist-info}/entry_points.txt +0 -0
- {dt_extensions_sdk-1.1.14.dist-info → dt_extensions_sdk-1.1.16.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dt-extensions-sdk
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.16
|
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=5SE6zz8YNj3cZnRJ6gzkBsJ3yLzLCTp4BjtDtYA4pTI,115
|
2
2
|
dynatrace_extension/__init__.py,sha256=XYHyWducrLWengm6jcCZMYAHzaQwQfoJKzKT4QvhTxE,779
|
3
3
|
dynatrace_extension/cli/__init__.py,sha256=eg2YQkeboIfJ_hcUGp1WFEvT-moa2qGGN-L9RjTbxCM,128
|
4
4
|
dynatrace_extension/cli/main.py,sha256=3KLvB2HZZe-tZKyB3n236N75ja5hGEMwxV-UaGyXxvE,17393
|
@@ -8,17 +8,17 @@ dynatrace_extension/cli/create/create.py,sha256=Wkkp4AuRID18k9EUJdVZ3GP2US35OF5h
|
|
8
8
|
dynatrace_extension/cli/create/extension_template/.gitignore.template,sha256=k8e-DOj0fYnXYjlLOCHoN5GBgtkNXHAYEfEWr3_YZV0,3238
|
9
9
|
dynatrace_extension/cli/create/extension_template/README.md.template,sha256=VUkh1AGyHJ_7hmxaGGhwiHys82VR16ii92_WvuhKHTY,670
|
10
10
|
dynatrace_extension/cli/create/extension_template/activation.json.template,sha256=8sO0WcqhoQouRHfy_V5KhJXdNYbBxc73VOcxLQKylzs,272
|
11
|
-
dynatrace_extension/cli/create/extension_template/setup.py.template,sha256=
|
11
|
+
dynatrace_extension/cli/create/extension_template/setup.py.template,sha256=i38dH4uIN0XJ8v5Ag7vJOrb6WDeXJpbylEIeVavln_I,874
|
12
12
|
dynatrace_extension/cli/create/extension_template/extension/activationSchema.json.template,sha256=ufVIxeAkrrrhEnk-TPvYgdEKpAbiWXNvHS5t9iZoED0,3023
|
13
|
-
dynatrace_extension/cli/create/extension_template/extension/extension.yaml.template,sha256=
|
13
|
+
dynatrace_extension/cli/create/extension_template/extension/extension.yaml.template,sha256=hdj4kShGE2u7A7bcVKypXTR3GExGm690EHwsNIBRrC4,316
|
14
14
|
dynatrace_extension/cli/create/extension_template/extension_name/__init__.py.template,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
15
|
dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template,sha256=UTwxpOkHFZTShEztuZwbAz8TjmXmRGAGmr_fwE4u0ro,1301
|
16
16
|
dynatrace_extension/sdk/__init__.py,sha256=sh7MNjmyR0vt-ugkqEHXVqwTNLExfexS0CTK-QnULcw,89
|
17
17
|
dynatrace_extension/sdk/activation.py,sha256=s1ZToshWNptfmgu5NsZCI_WMsNM3-O8CSzzoauo62Uk,1523
|
18
18
|
dynatrace_extension/sdk/callback.py,sha256=61o2ui2gXO__sDuY-zGaNTGmkk1tdn-5fQs6Ik7EodE,5962
|
19
|
-
dynatrace_extension/sdk/communication.py,sha256=
|
19
|
+
dynatrace_extension/sdk/communication.py,sha256=zKiUP0oKPniLzcyJIHAoWl6jj_0DjZr4gzZGB9O794U,19239
|
20
20
|
dynatrace_extension/sdk/event.py,sha256=oyvcm8uTle-A1jKgXIsFwAvl-Ta2RKbFHVZv3sxTPmo,407
|
21
|
-
dynatrace_extension/sdk/extension.py,sha256=
|
21
|
+
dynatrace_extension/sdk/extension.py,sha256=6FSayHmh24SRrFZ5TOEe9pVxWDWN3LhU3eSu3INhDoU,41349
|
22
22
|
dynatrace_extension/sdk/helper.py,sha256=TyL6aSIN6lhoH2yHZw8NbhtixdvlyV5q6fDh5NPODdc,6753
|
23
23
|
dynatrace_extension/sdk/metric.py,sha256=QwrfrmFdj-IddZxAZlZrch62TWKDtzrDU88FwBIv30E,3808
|
24
24
|
dynatrace_extension/sdk/runtime.py,sha256=JgP_qVomatVw85ZuAjbR0S-rzrK5U9JwSZXwfQDKNA4,2869
|
@@ -26,8 +26,8 @@ dynatrace_extension/sdk/vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
|
|
26
26
|
dynatrace_extension/sdk/vendor/mureq/LICENSE,sha256=_rKBhB1pJYXjxjBCdOSIkv_slxWbhEXVBXXZs1MdpQQ,684
|
27
27
|
dynatrace_extension/sdk/vendor/mureq/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
28
|
dynatrace_extension/sdk/vendor/mureq/mureq.py,sha256=gKzGiPmZ2g74Nb8K_6bu0f2coWZHZiZ2aXGzG2Pimlg,15102
|
29
|
-
dt_extensions_sdk-1.1.
|
30
|
-
dt_extensions_sdk-1.1.
|
31
|
-
dt_extensions_sdk-1.1.
|
32
|
-
dt_extensions_sdk-1.1.
|
33
|
-
dt_extensions_sdk-1.1.
|
29
|
+
dt_extensions_sdk-1.1.16.dist-info/METADATA,sha256=O_O8uBSihvwD_GTv5PMWe2exjNtiM7uE-Kt4iOZsdEM,2794
|
30
|
+
dt_extensions_sdk-1.1.16.dist-info/WHEEL,sha256=9QBuHhg6FNW7lppboF2vKVbCGTVzsFykgRQjjlajrhA,87
|
31
|
+
dt_extensions_sdk-1.1.16.dist-info/entry_points.txt,sha256=pweyOCgENGHjOlT6_kXYaBPOrE3p18K0UettqnNlnoE,55
|
32
|
+
dt_extensions_sdk-1.1.16.dist-info/licenses/LICENSE.txt,sha256=k7kok_OTpJ5sfb5ANni8wu-Q1lXw8OQjNZXdrTGhFKc,1087
|
33
|
+
dt_extensions_sdk-1.1.16.dist-info/RECORD,,
|
dynatrace_extension/__about__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
name: %extension-prefix%%extension-name%
|
2
2
|
version: 0.0.1
|
3
|
-
minDynatraceVersion: "1.
|
3
|
+
minDynatraceVersion: "1.285"
|
4
4
|
author:
|
5
5
|
name: "Dynatrace"
|
6
6
|
|
@@ -8,10 +8,10 @@ python:
|
|
8
8
|
runtime:
|
9
9
|
module: %extension_name%
|
10
10
|
version:
|
11
|
-
min: "3.
|
11
|
+
min: "3.10"
|
12
12
|
|
13
13
|
activation:
|
14
14
|
remote:
|
15
15
|
path: activationSchema.json
|
16
16
|
local:
|
17
|
-
path: activationSchema.json
|
17
|
+
path: activationSchema.json
|
@@ -1,7 +1,23 @@
|
|
1
|
+
from pathlib import Path
|
1
2
|
from setuptools import setup, find_packages
|
2
3
|
|
4
|
+
|
5
|
+
def find_version() -> str:
|
6
|
+
version = "0.0.1"
|
7
|
+
extension_yaml_path = Path(__file__).parent / "extension" / "extension.yaml"
|
8
|
+
try:
|
9
|
+
with open(extension_yaml_path, encoding="utf-8") as f:
|
10
|
+
for line in f:
|
11
|
+
if line.startswith("version"):
|
12
|
+
version = line.split(" ")[-1].strip("\"")
|
13
|
+
break
|
14
|
+
except Exception:
|
15
|
+
pass
|
16
|
+
return version
|
17
|
+
|
18
|
+
|
3
19
|
setup(name="%extension_name%",
|
4
|
-
version=
|
20
|
+
version=find_version(),
|
5
21
|
description="%Extension_Name% python EF2 extension",
|
6
22
|
author="Dynatrace",
|
7
23
|
packages=find_packages(),
|
@@ -10,11 +10,12 @@ import random
|
|
10
10
|
import sys
|
11
11
|
import time
|
12
12
|
from abc import ABC, abstractmethod
|
13
|
+
from collections import deque
|
13
14
|
from dataclasses import dataclass
|
14
15
|
from enum import Enum
|
15
16
|
from itertools import islice
|
16
17
|
from pathlib import Path
|
17
|
-
from typing import Any, Iterable, List, TypeVar
|
18
|
+
from typing import Any, Dict, Iterable, List, TypeVar, Union
|
18
19
|
|
19
20
|
from .vendor.mureq.mureq import HTTPException, Response, request
|
20
21
|
|
@@ -22,6 +23,8 @@ CONTENT_TYPE_JSON = "application/json;charset=utf-8"
|
|
22
23
|
CONTENT_TYPE_PLAIN = "text/plain;charset=utf-8"
|
23
24
|
COUNT_METRIC_ITEMS_DICT = TypeVar("COUNT_METRIC_ITEMS_DICT", str, List[str])
|
24
25
|
MAX_MINT_LINES_PER_REQUEST = 1000
|
26
|
+
MAX_LOG_EVENTS_PER_REQUEST = 50_000
|
27
|
+
MAX_LOG_REQUEST_SIZE = 5_000_000
|
25
28
|
HTTP_BAD_REQUEST = 400
|
26
29
|
|
27
30
|
|
@@ -94,7 +97,7 @@ class CommunicationClient(ABC):
|
|
94
97
|
pass
|
95
98
|
|
96
99
|
@abstractmethod
|
97
|
-
def send_events(self, event: dict | list[dict], eec_enrichment: bool) -> dict | None:
|
100
|
+
def send_events(self, event: dict | list[dict], eec_enrichment: bool) -> list[Union[dict | None]]:
|
98
101
|
pass
|
99
102
|
|
100
103
|
@abstractmethod
|
@@ -283,19 +286,26 @@ class HttpClient(CommunicationClient):
|
|
283
286
|
responses.append(mint_response)
|
284
287
|
return responses
|
285
288
|
|
286
|
-
def send_events(self, events: dict | list[dict], eec_enrichment: bool = True) -> dict | None:
|
289
|
+
def send_events(self, events: dict | list[dict], eec_enrichment: bool = True) -> list[dict | None]:
|
287
290
|
self.logger.debug(f"Sending log events: {events}")
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
291
|
+
|
292
|
+
responses = []
|
293
|
+
batches = divide_logs_into_batches([events] if isinstance(events, dict) else events)
|
294
|
+
|
295
|
+
for batch in batches:
|
296
|
+
try:
|
297
|
+
encoded_batch = json.dumps(batch).encode("utf-8")
|
298
|
+
eec_response = self._make_request(
|
299
|
+
self._events_url,
|
300
|
+
"POST",
|
301
|
+
encoded_batch,
|
302
|
+
extra_headers={"Content-Type": CONTENT_TYPE_JSON, "eec-enrichment": str(eec_enrichment).lower()},
|
303
|
+
).json()
|
304
|
+
responses.append(eec_response)
|
305
|
+
except json.JSONDecodeError:
|
306
|
+
responses.append(None)
|
307
|
+
|
308
|
+
return responses
|
299
309
|
|
300
310
|
def send_sfm_metrics(self, mint_lines: list[str]) -> MintResponse:
|
301
311
|
mint_data = "\n".join(mint_lines).encode("utf-8")
|
@@ -448,6 +458,46 @@ def divide_into_chunks(iterable: Iterable, chunk_size: int) -> Iterable:
|
|
448
458
|
return
|
449
459
|
yield subset
|
450
460
|
|
461
|
+
def divide_logs_into_batches(logs: list[dict]):
|
462
|
+
"""
|
463
|
+
Yield successive batches from a list of log events, according to sizing limitations
|
464
|
+
imposed by the EEC: 5 MB payload, 50,000 events
|
465
|
+
|
466
|
+
:param logs: The list of log events
|
467
|
+
"""
|
468
|
+
events_left = len(logs)
|
469
|
+
events = deque(logs)
|
470
|
+
|
471
|
+
batch = []
|
472
|
+
batch_size = 0
|
473
|
+
batch_items = 0
|
474
|
+
|
475
|
+
while events_left > 0:
|
476
|
+
if batch_items == MAX_LOG_EVENTS_PER_REQUEST:
|
477
|
+
yield batch
|
478
|
+
batch = []
|
479
|
+
batch_size = 0
|
480
|
+
batch_items = 0
|
481
|
+
continue
|
482
|
+
|
483
|
+
event = events.popleft()
|
484
|
+
events_left -= 1
|
485
|
+
|
486
|
+
if event is not None:
|
487
|
+
event = json.dumps(event).encode("utf-8")
|
488
|
+
event_size = len(event)
|
489
|
+
|
490
|
+
if batch_size + event_size >= MAX_LOG_REQUEST_SIZE:
|
491
|
+
yield batch
|
492
|
+
batch = [event]
|
493
|
+
batch_size = event_size
|
494
|
+
batch_items = 1
|
495
|
+
else:
|
496
|
+
batch.append(event)
|
497
|
+
batch_size += event_size
|
498
|
+
batch_items += 1
|
499
|
+
else:
|
500
|
+
yield batch
|
451
501
|
|
452
502
|
@dataclass
|
453
503
|
class MintResponse:
|
@@ -9,6 +9,7 @@ import sys
|
|
9
9
|
import threading
|
10
10
|
import time
|
11
11
|
from argparse import ArgumentParser
|
12
|
+
from collections import deque
|
12
13
|
from concurrent.futures import ThreadPoolExecutor
|
13
14
|
from datetime import datetime, timedelta, timezone
|
14
15
|
from enum import Enum
|
@@ -79,14 +80,15 @@ class DtEventType(str, Enum):
|
|
79
80
|
https://docs.dynatrace.com/docs/dynatrace-api/environment-api/events-v2/post-event
|
80
81
|
"""
|
81
82
|
|
83
|
+
AVAILABILITY_EVENT = "AVAILABILITY_EVENT"
|
82
84
|
CUSTOM_INFO = "CUSTOM_INFO"
|
83
85
|
CUSTOM_ALERT = "CUSTOM_ALERT"
|
84
86
|
CUSTOM_ANNOTATION = "CUSTOM_ANNOTATION"
|
85
87
|
CUSTOM_CONFIGURATION = "CUSTOM_CONFIGURATION"
|
86
88
|
CUSTOM_DEPLOYMENT = "CUSTOM_DEPLOYMENT"
|
87
|
-
MARKED_FOR_TERMINATION = "MARKED_FOR_TERMINATION"
|
88
89
|
ERROR_EVENT = "ERROR_EVENT"
|
89
|
-
|
90
|
+
MARKED_FOR_TERMINATION = "MARKED_FOR_TERMINATION"
|
91
|
+
PERFORMANCE_EVENT = "PERFORMANCE_EVENT"
|
90
92
|
RESOURCE_CONTENTION_EVENT = "RESOURCE_CONTENTION_EVENT"
|
91
93
|
|
92
94
|
|
@@ -995,14 +997,16 @@ class Extension:
|
|
995
997
|
self._metrics.extend(lines)
|
996
998
|
|
997
999
|
def _send_events_internal(self, events: Union[dict, List[dict]]):
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1000
|
+
responses = self._client.send_events(events, self.log_event_enrichment)
|
1001
|
+
|
1002
|
+
for response in responses:
|
1003
|
+
with self._internal_callbacks_results_lock:
|
1004
|
+
self._internal_callbacks_results[self._send_events.__name__] = Status(StatusValue.OK)
|
1005
|
+
if not response or "error" not in response or "message" not in response["error"]:
|
1006
|
+
return
|
1007
|
+
self._internal_callbacks_results[self._send_events.__name__] = Status(
|
1008
|
+
StatusValue.GENERIC_ERROR, response["error"]["message"]
|
1009
|
+
)
|
1006
1010
|
|
1007
1011
|
def _send_events(self, events: Union[dict, List[dict]]):
|
1008
1012
|
self._internal_executor.submit(self._send_events_internal, events)
|
@@ -1011,9 +1015,8 @@ class Extension:
|
|
1011
1015
|
self._client.send_dt_event(event)
|
1012
1016
|
|
1013
1017
|
def get_version(self) -> str:
|
1014
|
-
"""Return the version
|
1015
|
-
|
1016
|
-
return __version__
|
1018
|
+
"""Return the extension version."""
|
1019
|
+
return self.activation_config.version
|
1017
1020
|
|
1018
1021
|
@property
|
1019
1022
|
def techrule(self) -> str:
|
File without changes
|
File without changes
|
{dt_extensions_sdk-1.1.14.dist-info → dt_extensions_sdk-1.1.16.dist-info}/licenses/LICENSE.txt
RENAMED
File without changes
|