dt-extensions-sdk 1.3.1__py3-none-any.whl → 1.4.1__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.3.1.dist-info → dt_extensions_sdk-1.4.1.dist-info}/METADATA +2 -1
- {dt_extensions_sdk-1.3.1.dist-info → dt_extensions_sdk-1.4.1.dist-info}/RECORD +11 -10
- dynatrace_extension/__about__.py +1 -1
- dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template +8 -8
- dynatrace_extension/cli/create/extension_template/ruff.toml.template +77 -0
- dynatrace_extension/cli/create/extension_template/setup.py.template +14 -12
- dynatrace_extension/cli/main.py +50 -0
- dynatrace_extension/sdk/extension.py +40 -9
- {dt_extensions_sdk-1.3.1.dist-info → dt_extensions_sdk-1.4.1.dist-info}/WHEEL +0 -0
- {dt_extensions_sdk-1.3.1.dist-info → dt_extensions_sdk-1.4.1.dist-info}/entry_points.txt +0 -0
- {dt_extensions_sdk-1.3.1.dist-info → dt_extensions_sdk-1.4.1.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.
|
3
|
+
Version: 1.4.1
|
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
|
@@ -16,6 +16,7 @@ Requires-Python: <3.11,>=3.10
|
|
16
16
|
Provides-Extra: cli
|
17
17
|
Requires-Dist: dt-cli>=1.6.13; extra == 'cli'
|
18
18
|
Requires-Dist: pyyaml; extra == 'cli'
|
19
|
+
Requires-Dist: ruff; extra == 'cli'
|
19
20
|
Requires-Dist: typer[all]; extra == 'cli'
|
20
21
|
Description-Content-Type: text/markdown
|
21
22
|
|
@@ -1,25 +1,26 @@
|
|
1
|
-
dynatrace_extension/__about__.py,sha256
|
1
|
+
dynatrace_extension/__about__.py,sha256=sfmpNB9deUupD5FEf51kP87yHBs_W3e0oAyN3Zd3_vI,110
|
2
2
|
dynatrace_extension/__init__.py,sha256=BvQuknmA7ti3WJi3zEXZfY7aAxJrie37VNitWICsUvI,752
|
3
3
|
dynatrace_extension/cli/__init__.py,sha256=HCboY_eJPoqjFmoPDsBL8Jk6aNvank8K7JpkVrgwzUM,123
|
4
|
-
dynatrace_extension/cli/main.py,sha256=
|
4
|
+
dynatrace_extension/cli/main.py,sha256=afgSPayrpxwQjcCZzv9dIEbYBWs84708BbwoQr8XL4w,20157
|
5
5
|
dynatrace_extension/cli/schema.py,sha256=d8wKUodRiaU3hfSZDWVNpD15lBfhmif2oQ-k07IxcaA,3230
|
6
6
|
dynatrace_extension/cli/create/__init__.py,sha256=NfyOJCVlxs8dYtfDAMHS1Q5SJTuZcFzOg5rtaI-ZPRE,72
|
7
7
|
dynatrace_extension/cli/create/create.py,sha256=apXden2M93MDDDm7aa-Os-AEtUtyKbk_PsS56j32NK4,2708
|
8
8
|
dynatrace_extension/cli/create/extension_template/.gitignore.template,sha256=FPye23W8dqmked4HQBCDCAKFf1UbBGkwhKjQpgmXhdg,3101
|
9
9
|
dynatrace_extension/cli/create/extension_template/README.md.template,sha256=QcV0fYqJ1PHaouKdGQgzveJY5zAFBSICp7xSfgnoQj0,637
|
10
10
|
dynatrace_extension/cli/create/extension_template/activation.json.template,sha256=qX-Fgq_JhUWNYMe1-RMcjwQPzF4scJYGfGlBr043UiY,266
|
11
|
+
dynatrace_extension/cli/create/extension_template/ruff.toml.template,sha256=knGDPYHrdrlSDXpe3XNofcgAP-6XyzyHNqLd6Tr8bbs,1853
|
11
12
|
dynatrace_extension/cli/create/extension_template/secrets.json.template,sha256=fr-ya8lR0TiUmr6lf-PFko6RZw6sr54FxtMbqIWBVkA,36
|
12
|
-
dynatrace_extension/cli/create/extension_template/setup.py.template,sha256=
|
13
|
+
dynatrace_extension/cli/create/extension_template/setup.py.template,sha256=CPSx_mRKP6R273wFN-tJFQEsMNF2ktSO-I58mAWLM9M,829
|
13
14
|
dynatrace_extension/cli/create/extension_template/extension/activationSchema.json.template,sha256=me3DL_Q449q4VaOStTqaBL-gUkKnlafC8L2093O0LOY,2905
|
14
15
|
dynatrace_extension/cli/create/extension_template/extension/extension.yaml.template,sha256=qDyAURGXKsZBIPjW2s1BPhD-xOC8_FoBgA33HbsOkAU,299
|
15
16
|
dynatrace_extension/cli/create/extension_template/extension_name/__init__.py.template,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
-
dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template,sha256=
|
17
|
+
dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template,sha256=cS79GVxJB-V-gocu4ZOjmZ54HXJNg89eXdLf89zDHJQ,1249
|
17
18
|
dynatrace_extension/sdk/__init__.py,sha256=RsqQ1heGyCmSK3fhuEKAcxQIRCg4gEK0-eSkIehL5Nc,86
|
18
19
|
dynatrace_extension/sdk/activation.py,sha256=goTbT1tD2kn8xfyXFdTy_cTZNcFPJpgbvQM8HOzKECA,1480
|
19
20
|
dynatrace_extension/sdk/callback.py,sha256=eMpC0F3fCI82mWHIFgmy9QmKl7Kq_9dSaanHdV6o7hA,6511
|
20
21
|
dynatrace_extension/sdk/communication.py,sha256=QkJgEBblOen-jmvsb3ZfYZYglYUc7jHbkEgPtRj9l6w,19123
|
21
22
|
dynatrace_extension/sdk/event.py,sha256=J261imbFKpxfuAQ6Nfu3RRcsIQKKivy6fme1nww2g-8,388
|
22
|
-
dynatrace_extension/sdk/extension.py,sha256=
|
23
|
+
dynatrace_extension/sdk/extension.py,sha256=59hg3aUXbrkhvEB7za8jujv1LZQ4sSx4ot9scijadQU,44926
|
23
24
|
dynatrace_extension/sdk/helper.py,sha256=ZNrO9ao2hE3KQ934vAYD74k0fCr6QTG-_bAvbk9-hi8,6562
|
24
25
|
dynatrace_extension/sdk/metric.py,sha256=7VClzJCFJNDCxA-d69uTu1pdPtDZBTwq7fbafs_L6nQ,3690
|
25
26
|
dynatrace_extension/sdk/runtime.py,sha256=jyYsM1x-gMnW68eWq8IoZZZBarHgIcr_nVeGDDgpRDk,2802
|
@@ -28,8 +29,8 @@ dynatrace_extension/sdk/vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
|
|
28
29
|
dynatrace_extension/sdk/vendor/mureq/LICENSE,sha256=8AVcgZgiT_mvK1fOofXtRRr2f1dRXS_K21NuxQgP4VM,671
|
29
30
|
dynatrace_extension/sdk/vendor/mureq/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
31
|
dynatrace_extension/sdk/vendor/mureq/mureq.py,sha256=znF4mvzk5L03CLNozRz8UpK-fMijmSkObDFwlbhwLUg,14656
|
31
|
-
dt_extensions_sdk-1.
|
32
|
-
dt_extensions_sdk-1.
|
33
|
-
dt_extensions_sdk-1.
|
34
|
-
dt_extensions_sdk-1.
|
35
|
-
dt_extensions_sdk-1.
|
32
|
+
dt_extensions_sdk-1.4.1.dist-info/METADATA,sha256=MxsxFe30Bn3TW-Gpdul4OrkySRE6JHb_bDxWKZAWkCo,2721
|
33
|
+
dt_extensions_sdk-1.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
34
|
+
dt_extensions_sdk-1.4.1.dist-info/entry_points.txt,sha256=pweyOCgENGHjOlT6_kXYaBPOrE3p18K0UettqnNlnoE,55
|
35
|
+
dt_extensions_sdk-1.4.1.dist-info/licenses/LICENSE.txt,sha256=3Zihv0lOVYHNfDkJC-tUAU6euP9r2NexsDW4w-zqgVk,1078
|
36
|
+
dt_extensions_sdk-1.4.1.dist-info/RECORD,,
|
dynatrace_extension/__about__.py
CHANGED
@@ -2,7 +2,6 @@ from dynatrace_extension import Extension, Status, StatusValue
|
|
2
2
|
|
3
3
|
|
4
4
|
class ExtensionImpl(Extension):
|
5
|
-
|
6
5
|
def query(self):
|
7
6
|
"""
|
8
7
|
The query method is automatically scheduled to run every minute
|
@@ -11,22 +10,24 @@ class ExtensionImpl(Extension):
|
|
11
10
|
|
12
11
|
for endpoint in self.activation_config["endpoints"]:
|
13
12
|
url = endpoint["url"]
|
14
|
-
user = endpoint["user"]
|
15
|
-
password = endpoint["password"]
|
13
|
+
# user = endpoint["user"]
|
14
|
+
# password = endpoint["password"]
|
16
15
|
self.logger.debug(f"Running endpoint with url '{url}'")
|
17
16
|
|
18
17
|
# Your extension code goes here, e.g.
|
19
18
|
# response = requests.get(url, auth=(user, password))
|
20
19
|
|
21
20
|
# Report metrics with
|
22
|
-
self.report_metric("
|
21
|
+
self.report_metric("metric_key", 1, dimensions={"key": "value"})
|
23
22
|
|
24
23
|
self.logger.info("query method ended for %extension_name%.")
|
25
24
|
|
26
25
|
def fastcheck(self) -> Status:
|
27
26
|
"""
|
28
|
-
|
29
|
-
If this
|
27
|
+
Use to check if the extension can run.
|
28
|
+
If this Activegate cannot run this extension, you can
|
29
|
+
raise an Exception or return StatusValue.ERROR.
|
30
|
+
This does not run for OneAgent extensions.
|
30
31
|
"""
|
31
32
|
return Status(StatusValue.OK)
|
32
33
|
|
@@ -35,6 +36,5 @@ def main():
|
|
35
36
|
ExtensionImpl(name="%extension_name%").run()
|
36
37
|
|
37
38
|
|
38
|
-
|
39
|
-
if __name__ == '__main__':
|
39
|
+
if __name__ == "__main__":
|
40
40
|
main()
|
@@ -0,0 +1,77 @@
|
|
1
|
+
exclude = [
|
2
|
+
".bzr",
|
3
|
+
".direnv",
|
4
|
+
".eggs",
|
5
|
+
".git",
|
6
|
+
".git-rewrite",
|
7
|
+
".hg",
|
8
|
+
".ipynb_checkpoints",
|
9
|
+
".mypy_cache",
|
10
|
+
".nox",
|
11
|
+
".pants.d",
|
12
|
+
".pyenv",
|
13
|
+
".pytest_cache",
|
14
|
+
".pytype",
|
15
|
+
".ruff_cache",
|
16
|
+
".svn",
|
17
|
+
".tox",
|
18
|
+
".venv",
|
19
|
+
".vscode",
|
20
|
+
"__pypackages__",
|
21
|
+
"_build",
|
22
|
+
"buck-out",
|
23
|
+
"build",
|
24
|
+
"dist",
|
25
|
+
"node_modules",
|
26
|
+
"site-packages",
|
27
|
+
"venv",
|
28
|
+
"windows.py", # windows run as
|
29
|
+
"windows_runas.py", # windows run as
|
30
|
+
"*grpc.py", # automatically generated grpc files
|
31
|
+
"mureq.py", # a replacement for requests
|
32
|
+
"vendor", # vendored dependencies
|
33
|
+
"alembic", # alembic migrations
|
34
|
+
"oci", # special case for an extension
|
35
|
+
"pymqi", # special case for an extension
|
36
|
+
"lib" # some extensions commit a lib folder
|
37
|
+
]
|
38
|
+
|
39
|
+
line-length = 110
|
40
|
+
indent-width = 4
|
41
|
+
|
42
|
+
# Assume Python 3.10
|
43
|
+
target-version = "py310"
|
44
|
+
|
45
|
+
[lint]
|
46
|
+
select = ["E", "F", "W", "C90", "I", "N", "UP", "B", "A", "FA", "T20", "Q", "RET", "SIM", "ARG", "PTH", "C"]
|
47
|
+
ignore = [
|
48
|
+
"T201", # we allow print because these are logged into the extension logs
|
49
|
+
"PTH123" # open is used too frequently to open files
|
50
|
+
]
|
51
|
+
|
52
|
+
# Allow fix for all enabled rules (when `--fix`) is provided.
|
53
|
+
fixable = ["ALL"]
|
54
|
+
unfixable = []
|
55
|
+
|
56
|
+
# Allow unused variables when underscore-prefixed.
|
57
|
+
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
58
|
+
|
59
|
+
[lint.mccabe]
|
60
|
+
# Flag errors (`C901`) whenever the complexity level exceeds 20.
|
61
|
+
max-complexity = 20
|
62
|
+
|
63
|
+
[format]
|
64
|
+
# Like Black, use double quotes for strings.
|
65
|
+
quote-style = "double"
|
66
|
+
|
67
|
+
# Like Black, indent with spaces, rather than tabs.
|
68
|
+
indent-style = "space"
|
69
|
+
|
70
|
+
# Like Black, respect magic trailing commas.
|
71
|
+
skip-magic-trailing-comma = false
|
72
|
+
|
73
|
+
# Like Black, automatically detect the appropriate line ending.
|
74
|
+
line-ending = "auto"
|
75
|
+
|
76
|
+
docstring-code-format = false
|
77
|
+
docstring-code-line-length = "dynamic"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from pathlib import Path
|
2
|
-
|
2
|
+
|
3
|
+
from setuptools import find_packages, setup
|
3
4
|
|
4
5
|
|
5
6
|
def find_version() -> str:
|
@@ -9,20 +10,21 @@ def find_version() -> str:
|
|
9
10
|
with open(extension_yaml_path, encoding="utf-8") as f:
|
10
11
|
for line in f:
|
11
12
|
if line.startswith("version"):
|
12
|
-
version = line.split(" ")[-1].strip("
|
13
|
+
version = line.split(" ")[-1].strip('"')
|
13
14
|
break
|
14
15
|
except Exception:
|
15
16
|
pass
|
16
17
|
return version
|
17
18
|
|
18
19
|
|
19
|
-
setup(
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
setup(
|
21
|
+
name="%extension_name%",
|
22
|
+
version=find_version(),
|
23
|
+
description="%Extension_Name% python EF2 extension",
|
24
|
+
author="Dynatrace",
|
25
|
+
packages=find_packages(),
|
26
|
+
python_requires=">=3.10",
|
27
|
+
include_package_data=True,
|
28
|
+
install_requires=["dt-extensions-sdk"],
|
29
|
+
extras_require={"dev": ["dt-extensions-sdk[cli]"]},
|
30
|
+
)
|
dynatrace_extension/cli/main.py
CHANGED
@@ -425,6 +425,56 @@ def create(extension_name: str, output: Path = typer.Option(None, "--output", "-
|
|
425
425
|
console.print(f"Extension created at {extension_path}", style="bold green")
|
426
426
|
|
427
427
|
|
428
|
+
@app.command(
|
429
|
+
"format",
|
430
|
+
help="Runs ruff format on the extension code",
|
431
|
+
)
|
432
|
+
def fmt(extension_dir: Path = typer.Argument(".", help="Path to the python extension")):
|
433
|
+
"""
|
434
|
+
Runs ruff format on the extension code
|
435
|
+
|
436
|
+
:param extension_dir: The directory of the extension, by default this is the current directory
|
437
|
+
"""
|
438
|
+
run_process(["ruff", "format", str(extension_dir.resolve())])
|
439
|
+
|
440
|
+
|
441
|
+
@app.command(help="Runs ruff check on the extension code")
|
442
|
+
def lint(
|
443
|
+
extension_dir: Path = typer.Argument(".", help="Path to the python extension"),
|
444
|
+
fix: bool = typer.Option(False, "--fix", "-f", help="Fix linting issues"),
|
445
|
+
):
|
446
|
+
"""
|
447
|
+
Runs ruff lint on the extension code
|
448
|
+
|
449
|
+
:param extension_dir: The directory of the extension, by default this is the current directory
|
450
|
+
:param fix: If true, ask ruff to also fix the linting issues
|
451
|
+
"""
|
452
|
+
command = ["ruff", "check", "--exit-zero"]
|
453
|
+
if fix:
|
454
|
+
command.append("--fix")
|
455
|
+
command.append(str(extension_dir.resolve()))
|
456
|
+
run_process(command)
|
457
|
+
|
458
|
+
|
459
|
+
@app.command(help="Adds ruff rules if they don't exist already")
|
460
|
+
def ruff_init(extension_dir: Path = typer.Argument(".", help="Path to the python extension")):
|
461
|
+
"""
|
462
|
+
Adds ruff rules if they don't exist already
|
463
|
+
|
464
|
+
:param extension_dir: The directory of the extension, by default this is the current directory
|
465
|
+
"""
|
466
|
+
|
467
|
+
if (extension_dir / "ruff.toml").exists():
|
468
|
+
console.print(f"ruff.toml already exists in {extension_dir.resolve()}, skipping", style="bold yellow")
|
469
|
+
return
|
470
|
+
else:
|
471
|
+
# create\extension_template\ruff.toml.template -> extension\ruff.toml
|
472
|
+
ruff_template = Path(__file__).parent / "create" / "extension_template" / "ruff.toml.template"
|
473
|
+
ruff_file = extension_dir / "ruff.toml"
|
474
|
+
shutil.copy(ruff_template, ruff_file)
|
475
|
+
console.print(f"Added ruff.toml to {extension_dir.resolve()}", style="bold green")
|
476
|
+
|
477
|
+
|
428
478
|
def run_process(
|
429
479
|
command: List[str], cwd: Optional[Path] = None, env: Optional[dict] = None, print_message: Optional[str] = None
|
430
480
|
):
|
@@ -215,6 +215,7 @@ class Extension:
|
|
215
215
|
"timediff": datetime.now() + TIME_DIFF_INTERVAL,
|
216
216
|
"heartbeat": datetime.now() + HEARTBEAT_INTERVAL,
|
217
217
|
"metrics": datetime.now() + METRIC_SENDING_INTERVAL,
|
218
|
+
"events": datetime.now() + METRIC_SENDING_INTERVAL,
|
218
219
|
"sfm_metrics": datetime.now() + SFM_METRIC_SENDING_INTERVAL,
|
219
220
|
}
|
220
221
|
|
@@ -227,6 +228,10 @@ class Extension:
|
|
227
228
|
self._metrics_lock = RLock()
|
228
229
|
self._metrics: List[str] = []
|
229
230
|
|
231
|
+
# Extension logs
|
232
|
+
self._logs_lock = RLock()
|
233
|
+
self._logs: List[dict] = []
|
234
|
+
|
230
235
|
# Self monitoring metrics
|
231
236
|
self._sfm_metrics_lock = Lock()
|
232
237
|
self._callbackSfmReport: Dict[str, WrappedCallback] = {}
|
@@ -505,6 +510,7 @@ class Extension:
|
|
505
510
|
properties: Optional[dict] = None,
|
506
511
|
timestamp: Optional[datetime] = None,
|
507
512
|
severity: Union[Severity, str] = Severity.INFO,
|
513
|
+
send_immediately: bool = False,
|
508
514
|
) -> None:
|
509
515
|
"""Report an event using log ingest.
|
510
516
|
|
@@ -514,6 +520,7 @@ class Extension:
|
|
514
520
|
properties: A dictionary of extra event properties
|
515
521
|
timestamp: The timestamp of the event, defaults to the current time
|
516
522
|
severity: The severity of the event, defaults to Severity.INFO
|
523
|
+
send_immediately: Option to directly schedule log to be sent without batching
|
517
524
|
"""
|
518
525
|
if timestamp is None:
|
519
526
|
timestamp = datetime.now(tz=timezone.utc)
|
@@ -530,7 +537,7 @@ class Extension:
|
|
530
537
|
**self._metadata,
|
531
538
|
**properties,
|
532
539
|
}
|
533
|
-
self._send_events(event)
|
540
|
+
self._send_events(event, send_immediately=send_immediately)
|
534
541
|
|
535
542
|
def report_dt_event(
|
536
543
|
self,
|
@@ -635,7 +642,7 @@ class Extension:
|
|
635
642
|
raise ValueError(msg)
|
636
643
|
self._send_dt_event(event)
|
637
644
|
|
638
|
-
def report_log_event(self, log_event: dict):
|
645
|
+
def report_log_event(self, log_event: dict, send_immediately: bool = False):
|
639
646
|
"""Report a custom log event using log ingest.
|
640
647
|
|
641
648
|
Note:
|
@@ -643,25 +650,28 @@ class Extension:
|
|
643
650
|
|
644
651
|
Args:
|
645
652
|
log_event: The log event dictionary.
|
653
|
+
send_immediately: Option to directly schedule log to be sent without batching
|
646
654
|
"""
|
647
|
-
self._send_events(log_event)
|
655
|
+
self._send_events(log_event, send_immediately=send_immediately)
|
648
656
|
|
649
|
-
def report_log_events(self, log_events: List[dict]):
|
657
|
+
def report_log_events(self, log_events: List[dict], send_immediately: bool = False):
|
650
658
|
"""Report a list of custom log events using log ingest.
|
651
659
|
|
652
660
|
Args:
|
653
661
|
log_events: The list of log events
|
662
|
+
send_immediately: Option to directly schedule log to be sent without batching
|
654
663
|
"""
|
655
|
-
self._send_events(log_events)
|
664
|
+
self._send_events(log_events, send_immediately=send_immediately)
|
656
665
|
|
657
|
-
def report_log_lines(self, log_lines: List[Union[str, bytes]]):
|
666
|
+
def report_log_lines(self, log_lines: List[Union[str, bytes]], send_immediately: bool = False):
|
658
667
|
"""Report a list of log lines using log ingest
|
659
668
|
|
660
669
|
Args:
|
661
670
|
log_lines: The list of log lines
|
671
|
+
send_immediately: Option to directly schedule log to be sent without batching
|
662
672
|
"""
|
663
673
|
events = [{"content": line} for line in log_lines]
|
664
|
-
self._send_events(events)
|
674
|
+
self._send_events(events, send_immediately=send_immediately)
|
665
675
|
|
666
676
|
@property
|
667
677
|
def enabled_feature_sets(self) -> dict[str, list[str]]:
|
@@ -819,6 +829,7 @@ class Extension:
|
|
819
829
|
for callback in self._scheduled_callbacks_before_run:
|
820
830
|
self._schedule_callback(callback)
|
821
831
|
self._metrics_iteration()
|
832
|
+
self._events_iteration()
|
822
833
|
self._sfm_metrics_iteration()
|
823
834
|
self._timediff_iteration()
|
824
835
|
self._scheduler.run()
|
@@ -838,6 +849,11 @@ class Extension:
|
|
838
849
|
next_timestamp = self._get_and_set_next_internal_callback_timestamp("metrics", METRIC_SENDING_INTERVAL)
|
839
850
|
self._scheduler.enterabs(next_timestamp, 1, self._metrics_iteration)
|
840
851
|
|
852
|
+
def _events_iteration(self):
|
853
|
+
self._internal_executor.submit(self._send_buffered_events)
|
854
|
+
next_timestamp = self._get_and_set_next_internal_callback_timestamp("events", METRIC_SENDING_INTERVAL)
|
855
|
+
self._scheduler.enterabs(next_timestamp, 1, self._events_iteration)
|
856
|
+
|
841
857
|
def _sfm_metrics_iteration(self):
|
842
858
|
self._internal_executor.submit(self._send_sfm_metrics)
|
843
859
|
next_timestamp = self._get_and_set_next_internal_callback_timestamp("sfm_metrics", SFM_METRIC_SENDING_INTERVAL)
|
@@ -1044,8 +1060,23 @@ class Extension:
|
|
1044
1060
|
with self._internal_callbacks_results_lock:
|
1045
1061
|
self._internal_callbacks_results[self._send_events.__name__] = Status(StatusValue.GENERIC_ERROR, str(e))
|
1046
1062
|
|
1047
|
-
def _send_events(self, events: Union[dict, List[dict]]):
|
1048
|
-
|
1063
|
+
def _send_events(self, events: Union[dict, List[dict]], send_immediately: bool = False):
|
1064
|
+
if send_immediately:
|
1065
|
+
self._internal_executor.submit(self._send_events_internal, events)
|
1066
|
+
return
|
1067
|
+
with self._logs_lock:
|
1068
|
+
if isinstance(events, dict):
|
1069
|
+
self._logs.append(events)
|
1070
|
+
elif isinstance(events, list):
|
1071
|
+
self._logs.extend(events)
|
1072
|
+
else:
|
1073
|
+
self.logger.error(f"Invalid log format: {events}")
|
1074
|
+
|
1075
|
+
def _send_buffered_events(self):
|
1076
|
+
with self._logs_lock:
|
1077
|
+
if len(self._logs) > 0:
|
1078
|
+
self._send_events_internal(self._logs)
|
1079
|
+
self._logs = []
|
1049
1080
|
|
1050
1081
|
def _send_dt_event(self, event: dict[str, str | int | dict[str, str]]):
|
1051
1082
|
self._client.send_dt_event(event)
|
File without changes
|
File without changes
|
{dt_extensions_sdk-1.3.1.dist-info → dt_extensions_sdk-1.4.1.dist-info}/licenses/LICENSE.txt
RENAMED
File without changes
|