dt-extensions-sdk 1.1.14__tar.gz → 1.1.16__tar.gz

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.
Files changed (85) hide show
  1. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/PKG-INFO +1 -1
  2. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/conf.py +1 -1
  3. dt_extensions_sdk-1.1.16/docs/guides/building.rst +129 -0
  4. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/guides/extension_structure.rst +2 -2
  5. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/index.rst +1 -0
  6. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/__about__.py +1 -1
  7. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/extension_template/extension/extension.yaml.template +3 -3
  8. dt_extensions_sdk-1.1.16/dynatrace_extension/cli/create/extension_template/setup.py.template +28 -0
  9. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/communication.py +64 -14
  10. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/extension.py +16 -13
  11. dt_extensions_sdk-1.1.16/test.py +23 -0
  12. dt_extensions_sdk-1.1.16/test.txt +1 -0
  13. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/cli/test_types.py +3 -3
  14. dt_extensions_sdk-1.1.14/dynatrace_extension/cli/create/extension_template/setup.py.template +0 -12
  15. dt_extensions_sdk-1.1.14/extension.pkl +0 -0
  16. dt_extensions_sdk-1.1.14/test.py +0 -19
  17. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/.github/workflows/gh-pages-docs.yml +0 -0
  18. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/.github/workflows/publish.yml +0 -0
  19. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/.gitignore +0 -0
  20. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/LICENSE.txt +0 -0
  21. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/README.md +0 -0
  22. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/dt-sdk-header.png +0 -0
  23. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/dt-sdk-logo.png +0 -0
  24. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/favicon.ico +0 -0
  25. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/img/migrate-01-new-extension.png +0 -0
  26. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/img/migrate-02-type.png +0 -0
  27. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/img/migrate-03-import.png +0 -0
  28. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/img/migrate-04-import-remote.png +0 -0
  29. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/img/migrate-05-activation.png +0 -0
  30. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/_static/img/migrate-06-activation-config.png +0 -0
  31. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/api/events/event_severity.rst +0 -0
  32. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/api/events/event_type.rst +0 -0
  33. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/api/events/index.rst +0 -0
  34. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/api/extension.rst +0 -0
  35. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/api/metrics/index.rst +0 -0
  36. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/api/metrics/metric.rst +0 -0
  37. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/api/metrics/metric_type.rst +0 -0
  38. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/assemble.rst +0 -0
  39. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/build.rst +0 -0
  40. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/create.rst +0 -0
  41. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/gencerts.rst +0 -0
  42. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/help.rst +0 -0
  43. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/run.rst +0 -0
  44. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/sign.rst +0 -0
  45. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/upload.rst +0 -0
  46. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/cli/wheel.rst +0 -0
  47. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/guides/installation.rst +0 -0
  48. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/guides/migration.rst +0 -0
  49. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/docs/requirements.txt +0 -0
  50. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/__init__.py +0 -0
  51. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/__init__.py +0 -0
  52. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/__init__.py +0 -0
  53. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/create.py +0 -0
  54. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/extension_template/.gitignore.template +0 -0
  55. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/extension_template/README.md.template +0 -0
  56. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/extension_template/activation.json.template +0 -0
  57. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/extension_template/extension/activationSchema.json.template +0 -0
  58. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/extension_template/extension_name/__init__.py.template +0 -0
  59. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template +0 -0
  60. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/main.py +0 -0
  61. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/cli/schema.py +0 -0
  62. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/__init__.py +0 -0
  63. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/activation.py +0 -0
  64. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/callback.py +0 -0
  65. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/event.py +0 -0
  66. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/helper.py +0 -0
  67. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/metric.py +0 -0
  68. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/runtime.py +0 -0
  69. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/vendor/__init__.py +0 -0
  70. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/vendor/mureq/LICENSE +0 -0
  71. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/vendor/mureq/__init__.py +0 -0
  72. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/dynatrace_extension/sdk/vendor/mureq/mureq.py +0 -0
  73. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/pyproject.toml +0 -0
  74. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/__init__.py +0 -0
  75. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/cli/__init__.py +0 -0
  76. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/cli/test_dt_sdk.py +0 -0
  77. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/cli/test_templates.py +0 -0
  78. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/__init__.py +0 -0
  79. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/test_activation.py +0 -0
  80. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/test_callback.py +0 -0
  81. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/test_communication.py +0 -0
  82. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/test_extension.py +0 -0
  83. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/test_metric.py +0 -0
  84. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/test_runtime_properties.py +0 -0
  85. {dt_extensions_sdk-1.1.14 → dt_extensions_sdk-1.1.16}/tests/sdk/test_status.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dt-extensions-sdk
3
- Version: 1.1.14
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
@@ -88,7 +88,7 @@ html_theme_options = {
88
88
  "logo": "dt-sdk-logo.png",
89
89
  "logo_alt": "dt-sdk",
90
90
  "logo_url": "/",
91
- "github_url": "https://github.com/dynatrace-extensions/dt-extensions-python-sdk",
91
+ "github_url": "https://github.com/dynatrace-extensions/dt-extensions-python-sdk/tree/main/docs/",
92
92
  "footer_links": ",".join(
93
93
  [
94
94
  "Dynatrace|https://dynatrace.com/",
@@ -0,0 +1,129 @@
1
+ Building Extensions
2
+ ###################
3
+
4
+ | This guide provides some best practices on:
5
+ |
6
+
7
+ * Building extensions
8
+ * Python dependencies
9
+ * CI systems, offline installs
10
+
11
+ Native dependencies
12
+ ===================
13
+
14
+ | Some python libraries require "native" dependencies, they are not written in pure python and usually contain C, C++, Rust or other compiled languages code.
15
+ | This means that they might be compiled for a very specific version of python, or for a specific operating system.
16
+ |
17
+
18
+ | Examples:
19
+ |
20
+
21
+ * **requests** requires **charset_normalizer**, a **native dependency**
22
+
23
+
24
+ | If you navigate to the `charset-normalizer pypi page`_ you will see dozens of different wheel files.
25
+ | Each one of these files is compiled for a different version of python, and for a different operating system.
26
+ |
27
+ | Your extension will run on a Dynatrace **Activegate** or **OneAgent**, which is a Linux or Windows machine, and it has a specific version of python.
28
+ | This means that your extension must be built on a machine that has the same version of python as the Activegate.
29
+ |
30
+ | At this time, Dynatrace extensions run on **python 3.10**.
31
+ |
32
+ | When you build the extension with **dt-sdk build**, it downloads the dependencies **whl** files and places them in the lib folder of the extension.
33
+ | To obtain whl files for different a operating system than what the build machine is, the SDK provides the **--extra-platform** flag.
34
+ |
35
+ | In summary, when building from Windows, you should use:
36
+ |
37
+
38
+ .. code-block:: bash
39
+
40
+ dt-sdk build --extra-platform manylinux2014_x86_64
41
+
42
+
43
+ | To get the correct extra wheel files for linux. Note, **manylinux2014_x86_64** works for several packages, but not all of them.
44
+ | You need to investigate the dependencies of your extension to find the correct extra platform if that is the case.
45
+ |
46
+ | When building from Linux, you should use:
47
+ |
48
+
49
+
50
+ .. code-block:: bash
51
+
52
+ dt-sdk build --extra-platform win_amd64
53
+
54
+
55
+ | To get the correct extra wheel files for Windows.
56
+ |
57
+
58
+ PyPI Access
59
+ ===========
60
+
61
+ | When building extensions, the SDK downloads the dependencies from PyPI.
62
+ |
63
+ | In some organizations, you are not allowed to access the internet from the build machine.
64
+ | In most cases you will have either:
65
+ |
66
+
67
+ * A local PyPI mirror
68
+ * A directory with all the wheel files present
69
+
70
+ |
71
+ | Both of these solutions can be used with the SDK.
72
+ |
73
+
74
+ PyPI Mirror
75
+ """""""""""
76
+
77
+ | Suppose you have a local PyPi server running on http://my-pypi-server:8080.
78
+ |
79
+ | To use it with the SDK, run the build command as:
80
+ |
81
+
82
+ .. code-block:: bash
83
+
84
+ PIP_INDEX_URL=http://my-pypi-server:8080/simple PIP_TRUSTED_HOST=my-pypi-server dt-sdk build
85
+
86
+
87
+ | This will tell the SDK to use the local PyPI server to download the dependencies.
88
+ | The SDK uses **pip** under the covers, so all the environment variables that **pip** supports can be used with the SDK.
89
+ |
90
+ | Note, that assumes the build machine is a linux machine. If you are building from Windows on Powershell, you can use:
91
+ |
92
+
93
+ .. code-block:: bash
94
+
95
+ $ENV:PIP_INDEX_URL="http://my-pypi-server:8080/simple"; $ENV:PIP_TRUSTED_HOST="my-pypi-server"; dt-sdk build
96
+
97
+
98
+
99
+
100
+
101
+ Local Directory
102
+ """""""""""""""
103
+
104
+
105
+ | Another option is to manually download the different whl files you need, and place them in a directory on the build machine.
106
+ | In that case, that directory can be used as the source for the dependencies.
107
+ |
108
+
109
+ .. code-block:: bash
110
+
111
+ dt-sdk build --find-links /path/to/whl/files
112
+
113
+
114
+ | This will tell the SDK to use the directory as the source for the dependencies.
115
+ |
116
+
117
+ Musl vs libc
118
+ ============
119
+
120
+ | Extensions run on `libc`_ based systems, like Ubuntu, CentOS, Windows, etc.
121
+ | You should not use a `musl`_ based system, like Alpine, to build extensions.
122
+ |
123
+ | This means that if you are using a docker container to build the extension, you should use the **python:3.10** image, or any other image that is based on a `libc`_ system.
124
+ |
125
+ | The reason for this is that a **musl** based system will download native whl files that are not compatible with **libc** based systems.
126
+
127
+ .. _charset-normalizer pypi page: https://pypi.org/project/charset-normalizer/#files
128
+ .. _musl: https://musl.libc.org/
129
+ .. _libc: https://en.wikipedia.org/wiki/C_standard_library
@@ -33,7 +33,7 @@ Here is what a sample extension definition looks like:
33
33
 
34
34
  name: custom:my-extension
35
35
  version: 0.0.1
36
- minDynatraceVersion: "1.253"
36
+ minDynatraceVersion: "1.285"
37
37
  author:
38
38
  name: "Dynatrace"
39
39
 
@@ -41,7 +41,7 @@ Here is what a sample extension definition looks like:
41
41
  runtime:
42
42
  module: my_extension
43
43
  version:
44
- min: "3.9"
44
+ min: "3.10"
45
45
 
46
46
  activation:
47
47
  remote:
@@ -273,6 +273,7 @@ Documentation
273
273
 
274
274
  guides/installation
275
275
  guides/extension_structure
276
+ guides/building
276
277
  guides/migration
277
278
 
278
279
  .. toctree::
@@ -2,4 +2,4 @@
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
4
 
5
- __version__ = "1.1.14"
5
+ __version__ = "1.1.16"
@@ -1,6 +1,6 @@
1
1
  name: %extension-prefix%%extension-name%
2
2
  version: 0.0.1
3
- minDynatraceVersion: "1.253"
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.9"
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
@@ -0,0 +1,28 @@
1
+ from pathlib import Path
2
+ from setuptools import setup, find_packages
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
+
19
+ setup(name="%extension_name%",
20
+ version=find_version(),
21
+ description="%Extension_Name% python EF2 extension",
22
+ author="Dynatrace",
23
+ packages=find_packages(),
24
+ python_requires=">=3.10",
25
+ include_package_data=True,
26
+ install_requires=["dt-extensions-sdk"],
27
+ extras_require={"dev": ["dt-extensions-sdk[cli]"]},
28
+ )
@@ -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
- event_data = json.dumps(events).encode("utf-8")
289
- try:
290
- # EEC returns empty body on success
291
- return self._make_request(
292
- self._events_url,
293
- "POST",
294
- event_data,
295
- extra_headers={"Content-Type": CONTENT_TYPE_JSON, "eec-enrichment": str(eec_enrichment).lower()},
296
- ).json()
297
- except json.JSONDecodeError:
298
- return None
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
- AVAILABILITY_EVENT = "AVAILABILITY_EVENT"
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
- response = self._client.send_events(events, self.log_event_enrichment)
999
- with self._internal_callbacks_results_lock:
1000
- self._internal_callbacks_results[self._send_events.__name__] = Status(StatusValue.OK)
1001
- if not response or "error" not in response or "message" not in response["error"]:
1002
- return
1003
- self._internal_callbacks_results[self._send_events.__name__] = Status(
1004
- StatusValue.GENERIC_ERROR, response["error"]["message"]
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 of extensions sdk library."""
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:
@@ -0,0 +1,23 @@
1
+ import os
2
+ import time
3
+ from concurrent.futures import ProcessPoolExecutor
4
+
5
+ from dynatrace_extension import Extension
6
+
7
+
8
+ class Mass(Extension):
9
+ def initialize(self):
10
+ with ProcessPoolExecutor(max_workers=4) as metric_executor:
11
+ f = metric_executor.submit(self.thing)
12
+ print(f.result())
13
+
14
+ @staticmethod
15
+ def thing():
16
+ time.sleep(5)
17
+ current_pid = os.getpid()
18
+ with open(r"D:\workspace\repos\github\dt-extensions-python-sdk\test.txt", "w") as f:
19
+ f.write(f"Hello, world! {current_pid}")
20
+
21
+ if __name__ == "__main__":
22
+ m = Mass()
23
+ m.run()
@@ -0,0 +1 @@
1
+ Hello, world! 21160
@@ -8,7 +8,7 @@ from dynatrace_extension.cli.schema import ExtensionYaml
8
8
  VALID_YAML = """
9
9
  name: custom:mulesoft-cloudhub
10
10
  version: 0.0.1
11
- minDynatraceVersion: "1.902"
11
+ minDynatraceVersion: "1.285"
12
12
  author:
13
13
  name: "Dynatrace"
14
14
 
@@ -16,7 +16,7 @@ python:
16
16
  runtime:
17
17
  module: mulesoft_cloudhub
18
18
  version:
19
- min: "3.9"
19
+ min: "3.10"
20
20
 
21
21
  activation:
22
22
  remote:
@@ -38,7 +38,7 @@ class TestTypes(TestCase):
38
38
  assert extension.min_dynatrace_version == "1.902"
39
39
  assert extension.author.name == "Dynatrace"
40
40
  assert extension.python.runtime.module == "mulesoft_cloudhub"
41
- assert extension.python.runtime.version.min_version == "3.9"
41
+ assert extension.python.runtime.version.min_version == "3.10"
42
42
  assert extension.python.activation.remote.path == "activationSchema.json"
43
43
  assert extension.python.activation.local is None
44
44
 
@@ -1,12 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(name="%extension_name%",
4
- version="0.0.1",
5
- description="%Extension_Name% python EF2 extension",
6
- author="Dynatrace",
7
- packages=find_packages(),
8
- python_requires=">=3.10",
9
- include_package_data=True,
10
- install_requires=["dt-extensions-sdk"],
11
- extras_require={"dev": ["dt-extensions-sdk[cli]"]},
12
- )
File without changes
@@ -1,19 +0,0 @@
1
- import time
2
- from concurrent.futures import ProcessPoolExecutor
3
- from datetime import timedelta
4
-
5
- from dynatrace_extension import Extension
6
- from dynatrace_extension.sdk.callback import WrappedCallback
7
-
8
-
9
- class Mass(Extension):
10
- def initialize(self):
11
- with ProcessPoolExecutor(max_workers=4) as metric_executor:
12
- metric_executor.submit(self.thing)
13
-
14
- def thing(self):
15
- print("EITA PORRA")
16
-
17
- if __name__ == "__main__":
18
- m = Mass()
19
- m.run()