hexkit 8.5.0__tar.gz → 8.6.0__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.
- {hexkit-8.5.0/src/hexkit.egg-info → hexkit-8.6.0}/PKG-INFO +12 -12
- {hexkit-8.5.0 → hexkit-8.6.0}/pyproject.toml +12 -12
- hexkit-8.6.0/src/hexkit/opentelemetry/__init__.py +29 -0
- hexkit-8.6.0/src/hexkit/opentelemetry/instrumentation.py +122 -0
- hexkit-8.6.0/src/hexkit/opentelemetry/testutils.py +141 -0
- {hexkit-8.5.0 → hexkit-8.6.0/src/hexkit.egg-info}/PKG-INFO +12 -12
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit.egg-info/SOURCES.txt +3 -1
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit.egg-info/requires.txt +11 -11
- hexkit-8.5.0/src/hexkit/opentelemetry.py +0 -76
- {hexkit-8.5.0 → hexkit-8.6.0}/LICENSE +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/MANIFEST.in +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/README.md +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/setup.cfg +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/__main__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/base.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/config.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/correlation.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/custom_types.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/log.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/dao.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/daopub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/daosub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/eventpub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/eventsub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/kvstore.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/protocols/objstorage.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/config.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/provider/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/provider/daosub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/provider/eventpub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/provider/eventsub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/provider/utils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/testcontainer.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/akafka/testutils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/config.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/migrations/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/migrations/_manager.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/migrations/_utils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/migrations/helpers.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/provider/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/provider/client.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/provider/dao.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/provider/kvstore.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/provider/utils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongodb/testutils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongokafka/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongokafka/config.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongokafka/provider/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongokafka/provider/daopub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongokafka/provider/persistent_pub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/mongokafka/testutils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/redis/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/redis/config.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/redis/provider/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/redis/provider/client.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/redis/provider/kvstore.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/redis/testutils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/config.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/provider/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/provider/kvstore.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/provider/objstorage.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/test_files/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/test_files/test_file1.yaml +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/test_files/test_file2.yaml +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/test_files/test_file3.yaml +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/test_files/test_file4.yaml +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/testutils/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/testutils/_fixtures.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/testutils/_typical_workflow.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/s3/testutils/_utils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/testing/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/testing/dao.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/testing/eventpub.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/testing/kvstore.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/testing/objstorage.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/vault/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/vault/config.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/vault/provider/__init__.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/vault/provider/client.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/vault/provider/kvstore.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/providers/vault/testutils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/py.typed +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit/utils.py +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit.egg-info/dependency_links.txt +0 -0
- {hexkit-8.5.0 → hexkit-8.6.0}/src/hexkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexkit
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.6.0
|
|
4
4
|
Summary: A Toolkit for Building Microservices using the Hexagonal Architecture
|
|
5
5
|
Author-email: "German Human Genome Phenome Archive (GHGA)" <contact@ghga.de>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -21,7 +21,7 @@ Classifier: Intended Audience :: Developers
|
|
|
21
21
|
Requires-Python: >=3.10
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
|
-
Requires-Dist: opentelemetry-api<2,>=1.
|
|
24
|
+
Requires-Dist: opentelemetry-api<2,>=1.44
|
|
25
25
|
Requires-Dist: pydantic<3,>=2.12
|
|
26
26
|
Requires-Dist: pydantic_settings<3,>=2.12
|
|
27
27
|
Requires-Dist: PyYAML<7,>=6
|
|
@@ -38,30 +38,30 @@ Requires-Dist: redis<8,>=7.1; extra == "redis"
|
|
|
38
38
|
Provides-Extra: vault
|
|
39
39
|
Requires-Dist: hvac<3,>=2.4; extra == "vault"
|
|
40
40
|
Provides-Extra: opentelemetry-base
|
|
41
|
-
Requires-Dist: opentelemetry-sdk<2,>=1.
|
|
42
|
-
Requires-Dist: opentelemetry-exporter-otlp<2,>=1.
|
|
43
|
-
Requires-Dist: opentelemetry-instrumentation>=0.
|
|
44
|
-
Requires-Dist: opentelemetry-instrumentation-httpx>=0.
|
|
45
|
-
Requires-Dist: opentelemetry-distro>=0.
|
|
41
|
+
Requires-Dist: opentelemetry-sdk<2,>=1.44; extra == "opentelemetry-base"
|
|
42
|
+
Requires-Dist: opentelemetry-exporter-otlp<2,>=1.44; extra == "opentelemetry-base"
|
|
43
|
+
Requires-Dist: opentelemetry-instrumentation>=0.65b0; extra == "opentelemetry-base"
|
|
44
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.65b0; extra == "opentelemetry-base"
|
|
45
|
+
Requires-Dist: opentelemetry-distro>=0.65b0; extra == "opentelemetry-base"
|
|
46
46
|
Provides-Extra: opentelemetry-akafka
|
|
47
47
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-akafka"
|
|
48
48
|
Requires-Dist: hexkit[akafka]; extra == "opentelemetry-akafka"
|
|
49
|
-
Requires-Dist: opentelemetry-instrumentation-aiokafka>=0.
|
|
49
|
+
Requires-Dist: opentelemetry-instrumentation-aiokafka>=0.65b0; extra == "opentelemetry-akafka"
|
|
50
50
|
Provides-Extra: opentelemetry-mongodb
|
|
51
51
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-mongodb"
|
|
52
52
|
Requires-Dist: hexkit[mongodb]; extra == "opentelemetry-mongodb"
|
|
53
|
-
Requires-Dist: opentelemetry-instrumentation-pymongo>=0.
|
|
53
|
+
Requires-Dist: opentelemetry-instrumentation-pymongo>=0.65b0; extra == "opentelemetry-mongodb"
|
|
54
54
|
Provides-Extra: opentelemetry-fastapi
|
|
55
55
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-fastapi"
|
|
56
|
-
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.
|
|
56
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.65b0; extra == "opentelemetry-fastapi"
|
|
57
57
|
Provides-Extra: opentelemetry-s3
|
|
58
58
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-s3"
|
|
59
59
|
Requires-Dist: hexkit[s3]; extra == "opentelemetry-s3"
|
|
60
|
-
Requires-Dist: opentelemetry-instrumentation-botocore>=0.
|
|
60
|
+
Requires-Dist: opentelemetry-instrumentation-botocore>=0.65b0; extra == "opentelemetry-s3"
|
|
61
61
|
Provides-Extra: opentelemetry-redis
|
|
62
62
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-redis"
|
|
63
63
|
Requires-Dist: hexkit[redis]; extra == "opentelemetry-redis"
|
|
64
|
-
Requires-Dist: opentelemetry-instrumentation-redis>=0.
|
|
64
|
+
Requires-Dist: opentelemetry-instrumentation-redis>=0.65b0; extra == "opentelemetry-redis"
|
|
65
65
|
Provides-Extra: opentelemetry
|
|
66
66
|
Requires-Dist: hexkit[opentelemetry-akafka]; extra == "opentelemetry"
|
|
67
67
|
Requires-Dist: hexkit[opentelemetry-mongodb]; extra == "opentelemetry"
|
|
@@ -23,10 +23,10 @@ classifiers = [
|
|
|
23
23
|
"Intended Audience :: Developers",
|
|
24
24
|
]
|
|
25
25
|
name = "hexkit"
|
|
26
|
-
version = "8.
|
|
26
|
+
version = "8.6.0"
|
|
27
27
|
description = "A Toolkit for Building Microservices using the Hexagonal Architecture"
|
|
28
28
|
dependencies = [
|
|
29
|
-
"opentelemetry-api >=1.
|
|
29
|
+
"opentelemetry-api >=1.44, <2",
|
|
30
30
|
"pydantic >=2.12, <3",
|
|
31
31
|
"pydantic_settings >=2.12, <3",
|
|
32
32
|
"PyYAML >=6, <7",
|
|
@@ -54,35 +54,35 @@ vault = [
|
|
|
54
54
|
"hvac >=2.4, <3",
|
|
55
55
|
]
|
|
56
56
|
opentelemetry-base = [
|
|
57
|
-
"opentelemetry-sdk >=1.
|
|
58
|
-
"opentelemetry-exporter-otlp >=1.
|
|
59
|
-
"opentelemetry-instrumentation >=0.
|
|
60
|
-
"opentelemetry-instrumentation-httpx >=0.
|
|
61
|
-
"opentelemetry-distro >=0.
|
|
57
|
+
"opentelemetry-sdk >=1.44, <2",
|
|
58
|
+
"opentelemetry-exporter-otlp >=1.44, <2",
|
|
59
|
+
"opentelemetry-instrumentation >=0.65b0",
|
|
60
|
+
"opentelemetry-instrumentation-httpx >=0.65b0",
|
|
61
|
+
"opentelemetry-distro >=0.65b0",
|
|
62
62
|
]
|
|
63
63
|
opentelemetry-akafka = [
|
|
64
64
|
"hexkit[opentelemetry-base]",
|
|
65
65
|
"hexkit[akafka]",
|
|
66
|
-
"opentelemetry-instrumentation-aiokafka >=0.
|
|
66
|
+
"opentelemetry-instrumentation-aiokafka >=0.65b0",
|
|
67
67
|
]
|
|
68
68
|
opentelemetry-mongodb = [
|
|
69
69
|
"hexkit[opentelemetry-base]",
|
|
70
70
|
"hexkit[mongodb]",
|
|
71
|
-
"opentelemetry-instrumentation-pymongo >=0.
|
|
71
|
+
"opentelemetry-instrumentation-pymongo >=0.65b0",
|
|
72
72
|
]
|
|
73
73
|
opentelemetry-fastapi = [
|
|
74
74
|
"hexkit[opentelemetry-base]",
|
|
75
|
-
"opentelemetry-instrumentation-fastapi >=0.
|
|
75
|
+
"opentelemetry-instrumentation-fastapi >=0.65b0",
|
|
76
76
|
]
|
|
77
77
|
opentelemetry-s3 = [
|
|
78
78
|
"hexkit[opentelemetry-base]",
|
|
79
79
|
"hexkit[s3]",
|
|
80
|
-
"opentelemetry-instrumentation-botocore >=0.
|
|
80
|
+
"opentelemetry-instrumentation-botocore >=0.65b0",
|
|
81
81
|
]
|
|
82
82
|
opentelemetry-redis = [
|
|
83
83
|
"hexkit[opentelemetry-base]",
|
|
84
84
|
"hexkit[redis]",
|
|
85
|
-
"opentelemetry-instrumentation-redis >=0.
|
|
85
|
+
"opentelemetry-instrumentation-redis >=0.65b0",
|
|
86
86
|
]
|
|
87
87
|
opentelemetry = [
|
|
88
88
|
"hexkit[opentelemetry-akafka]",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright 2021 - 2026 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln
|
|
2
|
+
# for the German Human Genome-Phenome Archive (GHGA)
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
"""Subpackage containing OpenTelemetry instrumentation and related utilities."""
|
|
18
|
+
|
|
19
|
+
from .instrumentation import (
|
|
20
|
+
OpenTelemetryConfig,
|
|
21
|
+
configure_opentelemetry,
|
|
22
|
+
instrument_installed_libraries,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"OpenTelemetryConfig",
|
|
27
|
+
"configure_opentelemetry",
|
|
28
|
+
"instrument_installed_libraries",
|
|
29
|
+
]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Copyright 2021 - 2026 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln
|
|
2
|
+
# for the German Human Genome-Phenome Archive (GHGA)
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""OpenTelemetry specific configuration code. This is gated behind the opentelemetry extra."""
|
|
17
|
+
|
|
18
|
+
import importlib
|
|
19
|
+
import logging
|
|
20
|
+
from typing import Annotated
|
|
21
|
+
|
|
22
|
+
from opentelemetry import trace
|
|
23
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
24
|
+
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
25
|
+
from opentelemetry.sdk.trace import SpanProcessor, TracerProvider
|
|
26
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
27
|
+
from opentelemetry.sdk.trace.sampling import ParentBasedTraceIdRatio
|
|
28
|
+
from pydantic import Field
|
|
29
|
+
from pydantic_settings import BaseSettings
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"OpenTelemetryConfig",
|
|
33
|
+
"configure_opentelemetry",
|
|
34
|
+
"instrument_installed_libraries",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
# Instrumentation modules corresponding to the `opentelemetry-*` optional extras.
|
|
40
|
+
# Each entry is only instrumented if its module is installed.
|
|
41
|
+
_INSTRUMENTOR_MODULES: tuple[tuple[str, str], ...] = (
|
|
42
|
+
("opentelemetry.instrumentation.httpx", "HTTPXClientInstrumentor"),
|
|
43
|
+
("opentelemetry.instrumentation.aiokafka", "AIOKafkaInstrumentor"),
|
|
44
|
+
("opentelemetry.instrumentation.pymongo", "PymongoInstrumentor"),
|
|
45
|
+
("opentelemetry.instrumentation.fastapi", "FastAPIInstrumentor"),
|
|
46
|
+
("opentelemetry.instrumentation.botocore", "BotocoreInstrumentor"),
|
|
47
|
+
("opentelemetry.instrumentation.redis", "RedisInstrumentor"),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def instrument_installed_libraries() -> None:
|
|
52
|
+
"""Run `.instrument()` for every instrumentation library that is installed."""
|
|
53
|
+
for module_name, class_name in _INSTRUMENTOR_MODULES:
|
|
54
|
+
try:
|
|
55
|
+
module = importlib.import_module(module_name)
|
|
56
|
+
except ImportError:
|
|
57
|
+
logger.debug("'%s' not installed, skipping instrumentation.", module_name)
|
|
58
|
+
continue
|
|
59
|
+
try:
|
|
60
|
+
instrumentor_class = getattr(module, class_name)
|
|
61
|
+
except AttributeError:
|
|
62
|
+
logger.warning(
|
|
63
|
+
"Could not instrument '%s' for '%s'.", class_name, module_name
|
|
64
|
+
)
|
|
65
|
+
instrumentor_class().instrument()
|
|
66
|
+
logger.info("Instrumented '%s' for '%s'.", class_name, module_name)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class OpenTelemetryConfig(BaseSettings):
|
|
70
|
+
"""OpenTelemetry specific configuration options"""
|
|
71
|
+
|
|
72
|
+
enable_opentelemetry: bool = Field(
|
|
73
|
+
default=False,
|
|
74
|
+
description="If set to true, this will run necessary setup code."
|
|
75
|
+
"If set to false, no setup code is run, which leaves tracing disabled.",
|
|
76
|
+
)
|
|
77
|
+
otel_trace_sampling_rate: Annotated[float, Field(strict=True, ge=0, le=1)] = Field(
|
|
78
|
+
default=1.0,
|
|
79
|
+
description="Determines which proportion of spans should be sampled. "
|
|
80
|
+
"A value of 1.0 means all and is equivalent to the previous behaviour. "
|
|
81
|
+
"Setting this to 0 will result in no spans being sampled, but this does not "
|
|
82
|
+
"automatically set `enable_opentelemetry` to False.",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def configure_opentelemetry(
|
|
87
|
+
*,
|
|
88
|
+
service_name: str,
|
|
89
|
+
config: OpenTelemetryConfig,
|
|
90
|
+
span_processor: SpanProcessor | None = None,
|
|
91
|
+
):
|
|
92
|
+
"""Configure all needed parts of OpenTelemetry.
|
|
93
|
+
|
|
94
|
+
This needs to be called before constructing any objects that are instrumented, e.g.
|
|
95
|
+
construction a FastAPI app before running this, will result in missing instrumentation.
|
|
96
|
+
|
|
97
|
+
Setup of the TracerProvider is done programmatically. If disabled, this is a no-op,
|
|
98
|
+
leaving the default no-op TracerProvider from the OpenTelemetry API in place.
|
|
99
|
+
|
|
100
|
+
By default, spans are exported via OTLP over HTTP using a `BatchSpanProcessor`.
|
|
101
|
+
"""
|
|
102
|
+
if not config.enable_opentelemetry:
|
|
103
|
+
logger.info("OpenTelemetry disabled via config.")
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
resource = Resource(attributes={SERVICE_NAME: service_name})
|
|
107
|
+
# Replace the default static sampler with a probabilistic one that honors parent
|
|
108
|
+
# span sampling decisions
|
|
109
|
+
# This should consistently yield full traces within a service but not necessarily
|
|
110
|
+
# across service boundaries
|
|
111
|
+
# With the default sampling rate, behaviour does not change, but this allows to
|
|
112
|
+
# introduce head sampling by adjusting a config option on the service side later on
|
|
113
|
+
sampler = ParentBasedTraceIdRatio(rate=config.otel_trace_sampling_rate)
|
|
114
|
+
|
|
115
|
+
# Initialize service specific TracerProvider
|
|
116
|
+
trace_provider = TracerProvider(resource=resource, sampler=sampler)
|
|
117
|
+
trace_provider.add_span_processor(
|
|
118
|
+
span_processor or BatchSpanProcessor(OTLPSpanExporter())
|
|
119
|
+
)
|
|
120
|
+
trace.set_tracer_provider(trace_provider)
|
|
121
|
+
|
|
122
|
+
instrument_installed_libraries()
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Copyright 2021 - 2026 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln
|
|
2
|
+
# for the German Human Genome-Phenome Archive (GHGA)
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
"""Utilities for testing code that relies on OpenTelemetry instrumentation.
|
|
18
|
+
|
|
19
|
+
Please note, only use for testing purposes.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from collections.abc import Generator
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
|
|
25
|
+
import pytest
|
|
26
|
+
from opentelemetry import trace
|
|
27
|
+
from opentelemetry.sdk.trace import ReadableSpan, TracerProvider
|
|
28
|
+
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
|
|
29
|
+
from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
|
|
30
|
+
InMemorySpanExporter,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from hexkit.custom_types import PytestScope
|
|
34
|
+
from hexkit.opentelemetry import OpenTelemetryConfig, configure_opentelemetry
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"OpenTelemetryFixture",
|
|
38
|
+
"get_otel_fixture",
|
|
39
|
+
"get_otel_provider_fixture",
|
|
40
|
+
"otel_fixture",
|
|
41
|
+
"otel_provider_fixture",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class OpenTelemetryFixture:
|
|
47
|
+
"""A fixture with utility methods for tests that verify emitted spans."""
|
|
48
|
+
|
|
49
|
+
exporter: InMemorySpanExporter
|
|
50
|
+
|
|
51
|
+
def reset(self) -> None:
|
|
52
|
+
"""Clear all previously captured spans."""
|
|
53
|
+
self.exporter.clear()
|
|
54
|
+
|
|
55
|
+
def get_finished_spans(self) -> tuple[ReadableSpan, ...]:
|
|
56
|
+
"""Return all spans finished so far, in the order they completed."""
|
|
57
|
+
return tuple(self.exporter.get_finished_spans())
|
|
58
|
+
|
|
59
|
+
def get_span_names(self) -> list[str]:
|
|
60
|
+
"""Return the names of all finished spans, in the order they completed."""
|
|
61
|
+
return [span.name for span in self.get_finished_spans()]
|
|
62
|
+
|
|
63
|
+
def assert_has_span(self, name: str) -> ReadableSpan:
|
|
64
|
+
"""Assert that a finished span with the given name exists and return it."""
|
|
65
|
+
for span in self.get_finished_spans():
|
|
66
|
+
if span.name == name:
|
|
67
|
+
return span
|
|
68
|
+
raise AssertionError(
|
|
69
|
+
f"No span named {name!r} found. Captured spans: {self.get_span_names()}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _otel_provider_fixture(
|
|
74
|
+
service_name: str = "test",
|
|
75
|
+
) -> Generator[OpenTelemetryFixture, None, None]:
|
|
76
|
+
"""Fixture function attaching an in-memory span exporter for the test session.
|
|
77
|
+
|
|
78
|
+
If OpenTelemetry has already been configured (e.g. because the app under test
|
|
79
|
+
calls `configure_opentelemetry()` on startup), this attaches to the resulting
|
|
80
|
+
TracerProvider so the exact same setup (sampler, resource, instrumented
|
|
81
|
+
libraries) is exercised. Otherwise, it configures one itself via
|
|
82
|
+
`configure_opentelemetry()` so the fixture also works standalone.
|
|
83
|
+
|
|
84
|
+
A `SimpleSpanProcessor` is used instead of the `BatchSpanProcessor` used for real
|
|
85
|
+
exports, so spans show up as soon as they end instead of on a batching interval.
|
|
86
|
+
"""
|
|
87
|
+
provider = trace.get_tracer_provider()
|
|
88
|
+
exporter = InMemorySpanExporter()
|
|
89
|
+
|
|
90
|
+
if not isinstance(provider, TracerProvider):
|
|
91
|
+
# No app under test has configured OpenTelemetry yet, so do it here, wiring
|
|
92
|
+
# up the in-memory exporter directly instead of the default OTLP exporter -
|
|
93
|
+
# this avoids pointless connection attempts against a collector in tests.
|
|
94
|
+
configure_opentelemetry(
|
|
95
|
+
service_name=service_name,
|
|
96
|
+
config=OpenTelemetryConfig(enable_opentelemetry=True),
|
|
97
|
+
span_processor=SimpleSpanProcessor(exporter),
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
# OpenTelemetry has already been configured (e.g. by the app under test),
|
|
101
|
+
# so attach to its existing TracerProvider instead of replacing it -
|
|
102
|
+
# OpenTelemetry only allows the global TracerProvider to be set once.
|
|
103
|
+
# Detaching after the test is not possible, as there's no stable public API for that
|
|
104
|
+
provider.add_span_processor(SimpleSpanProcessor(exporter))
|
|
105
|
+
|
|
106
|
+
yield OpenTelemetryFixture(exporter=exporter)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def get_otel_provider_fixture(
|
|
110
|
+
scope: PytestScope = "session", name: str = "otel_provider"
|
|
111
|
+
):
|
|
112
|
+
"""Get a fixture with desired scope and name that sets up span capturing.
|
|
113
|
+
|
|
114
|
+
By default, the session scope is used since only one `TracerProvider` can be
|
|
115
|
+
configured per process.
|
|
116
|
+
"""
|
|
117
|
+
return pytest.fixture(_otel_provider_fixture, scope=scope, name=name)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
otel_provider_fixture = get_otel_provider_fixture()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _otel_fixture(
|
|
124
|
+
otel_provider: OpenTelemetryFixture,
|
|
125
|
+
) -> Generator[OpenTelemetryFixture, None, None]:
|
|
126
|
+
"""Fixture function that gets a clean slate of captured spans for a single test."""
|
|
127
|
+
otel_provider.reset()
|
|
128
|
+
yield otel_provider
|
|
129
|
+
otel_provider.reset()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def get_otel_fixture(scope: PytestScope = "function", name: str = "otel"):
|
|
133
|
+
"""Get a fixture with desired scope and name for asserting on emitted spans.
|
|
134
|
+
|
|
135
|
+
By default, the function scope is used so captured spans don't leak between
|
|
136
|
+
tests, while the session scope is used for the underlying span capturing setup.
|
|
137
|
+
"""
|
|
138
|
+
return pytest.fixture(_otel_fixture, scope=scope, name=name)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
otel_fixture = get_otel_fixture()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexkit
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.6.0
|
|
4
4
|
Summary: A Toolkit for Building Microservices using the Hexagonal Architecture
|
|
5
5
|
Author-email: "German Human Genome Phenome Archive (GHGA)" <contact@ghga.de>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -21,7 +21,7 @@ Classifier: Intended Audience :: Developers
|
|
|
21
21
|
Requires-Python: >=3.10
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
|
-
Requires-Dist: opentelemetry-api<2,>=1.
|
|
24
|
+
Requires-Dist: opentelemetry-api<2,>=1.44
|
|
25
25
|
Requires-Dist: pydantic<3,>=2.12
|
|
26
26
|
Requires-Dist: pydantic_settings<3,>=2.12
|
|
27
27
|
Requires-Dist: PyYAML<7,>=6
|
|
@@ -38,30 +38,30 @@ Requires-Dist: redis<8,>=7.1; extra == "redis"
|
|
|
38
38
|
Provides-Extra: vault
|
|
39
39
|
Requires-Dist: hvac<3,>=2.4; extra == "vault"
|
|
40
40
|
Provides-Extra: opentelemetry-base
|
|
41
|
-
Requires-Dist: opentelemetry-sdk<2,>=1.
|
|
42
|
-
Requires-Dist: opentelemetry-exporter-otlp<2,>=1.
|
|
43
|
-
Requires-Dist: opentelemetry-instrumentation>=0.
|
|
44
|
-
Requires-Dist: opentelemetry-instrumentation-httpx>=0.
|
|
45
|
-
Requires-Dist: opentelemetry-distro>=0.
|
|
41
|
+
Requires-Dist: opentelemetry-sdk<2,>=1.44; extra == "opentelemetry-base"
|
|
42
|
+
Requires-Dist: opentelemetry-exporter-otlp<2,>=1.44; extra == "opentelemetry-base"
|
|
43
|
+
Requires-Dist: opentelemetry-instrumentation>=0.65b0; extra == "opentelemetry-base"
|
|
44
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.65b0; extra == "opentelemetry-base"
|
|
45
|
+
Requires-Dist: opentelemetry-distro>=0.65b0; extra == "opentelemetry-base"
|
|
46
46
|
Provides-Extra: opentelemetry-akafka
|
|
47
47
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-akafka"
|
|
48
48
|
Requires-Dist: hexkit[akafka]; extra == "opentelemetry-akafka"
|
|
49
|
-
Requires-Dist: opentelemetry-instrumentation-aiokafka>=0.
|
|
49
|
+
Requires-Dist: opentelemetry-instrumentation-aiokafka>=0.65b0; extra == "opentelemetry-akafka"
|
|
50
50
|
Provides-Extra: opentelemetry-mongodb
|
|
51
51
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-mongodb"
|
|
52
52
|
Requires-Dist: hexkit[mongodb]; extra == "opentelemetry-mongodb"
|
|
53
|
-
Requires-Dist: opentelemetry-instrumentation-pymongo>=0.
|
|
53
|
+
Requires-Dist: opentelemetry-instrumentation-pymongo>=0.65b0; extra == "opentelemetry-mongodb"
|
|
54
54
|
Provides-Extra: opentelemetry-fastapi
|
|
55
55
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-fastapi"
|
|
56
|
-
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.
|
|
56
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.65b0; extra == "opentelemetry-fastapi"
|
|
57
57
|
Provides-Extra: opentelemetry-s3
|
|
58
58
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-s3"
|
|
59
59
|
Requires-Dist: hexkit[s3]; extra == "opentelemetry-s3"
|
|
60
|
-
Requires-Dist: opentelemetry-instrumentation-botocore>=0.
|
|
60
|
+
Requires-Dist: opentelemetry-instrumentation-botocore>=0.65b0; extra == "opentelemetry-s3"
|
|
61
61
|
Provides-Extra: opentelemetry-redis
|
|
62
62
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-redis"
|
|
63
63
|
Requires-Dist: hexkit[redis]; extra == "opentelemetry-redis"
|
|
64
|
-
Requires-Dist: opentelemetry-instrumentation-redis>=0.
|
|
64
|
+
Requires-Dist: opentelemetry-instrumentation-redis>=0.65b0; extra == "opentelemetry-redis"
|
|
65
65
|
Provides-Extra: opentelemetry
|
|
66
66
|
Requires-Dist: hexkit[opentelemetry-akafka]; extra == "opentelemetry"
|
|
67
67
|
Requires-Dist: hexkit[opentelemetry-mongodb]; extra == "opentelemetry"
|
|
@@ -9,7 +9,6 @@ src/hexkit/config.py
|
|
|
9
9
|
src/hexkit/correlation.py
|
|
10
10
|
src/hexkit/custom_types.py
|
|
11
11
|
src/hexkit/log.py
|
|
12
|
-
src/hexkit/opentelemetry.py
|
|
13
12
|
src/hexkit/py.typed
|
|
14
13
|
src/hexkit/utils.py
|
|
15
14
|
src/hexkit.egg-info/PKG-INFO
|
|
@@ -17,6 +16,9 @@ src/hexkit.egg-info/SOURCES.txt
|
|
|
17
16
|
src/hexkit.egg-info/dependency_links.txt
|
|
18
17
|
src/hexkit.egg-info/requires.txt
|
|
19
18
|
src/hexkit.egg-info/top_level.txt
|
|
19
|
+
src/hexkit/opentelemetry/__init__.py
|
|
20
|
+
src/hexkit/opentelemetry/instrumentation.py
|
|
21
|
+
src/hexkit/opentelemetry/testutils.py
|
|
20
22
|
src/hexkit/protocols/__init__.py
|
|
21
23
|
src/hexkit/protocols/dao.py
|
|
22
24
|
src/hexkit/protocols/daopub.py
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
opentelemetry-api<2,>=1.
|
|
1
|
+
opentelemetry-api<2,>=1.44
|
|
2
2
|
pydantic<3,>=2.12
|
|
3
3
|
pydantic_settings<3,>=2.12
|
|
4
4
|
PyYAML<7,>=6
|
|
@@ -23,33 +23,33 @@ hexkit[opentelemetry-s3]
|
|
|
23
23
|
[opentelemetry-akafka]
|
|
24
24
|
hexkit[opentelemetry-base]
|
|
25
25
|
hexkit[akafka]
|
|
26
|
-
opentelemetry-instrumentation-aiokafka>=0.
|
|
26
|
+
opentelemetry-instrumentation-aiokafka>=0.65b0
|
|
27
27
|
|
|
28
28
|
[opentelemetry-base]
|
|
29
|
-
opentelemetry-sdk<2,>=1.
|
|
30
|
-
opentelemetry-exporter-otlp<2,>=1.
|
|
31
|
-
opentelemetry-instrumentation>=0.
|
|
32
|
-
opentelemetry-instrumentation-httpx>=0.
|
|
33
|
-
opentelemetry-distro>=0.
|
|
29
|
+
opentelemetry-sdk<2,>=1.44
|
|
30
|
+
opentelemetry-exporter-otlp<2,>=1.44
|
|
31
|
+
opentelemetry-instrumentation>=0.65b0
|
|
32
|
+
opentelemetry-instrumentation-httpx>=0.65b0
|
|
33
|
+
opentelemetry-distro>=0.65b0
|
|
34
34
|
|
|
35
35
|
[opentelemetry-fastapi]
|
|
36
36
|
hexkit[opentelemetry-base]
|
|
37
|
-
opentelemetry-instrumentation-fastapi>=0.
|
|
37
|
+
opentelemetry-instrumentation-fastapi>=0.65b0
|
|
38
38
|
|
|
39
39
|
[opentelemetry-mongodb]
|
|
40
40
|
hexkit[opentelemetry-base]
|
|
41
41
|
hexkit[mongodb]
|
|
42
|
-
opentelemetry-instrumentation-pymongo>=0.
|
|
42
|
+
opentelemetry-instrumentation-pymongo>=0.65b0
|
|
43
43
|
|
|
44
44
|
[opentelemetry-redis]
|
|
45
45
|
hexkit[opentelemetry-base]
|
|
46
46
|
hexkit[redis]
|
|
47
|
-
opentelemetry-instrumentation-redis>=0.
|
|
47
|
+
opentelemetry-instrumentation-redis>=0.65b0
|
|
48
48
|
|
|
49
49
|
[opentelemetry-s3]
|
|
50
50
|
hexkit[opentelemetry-base]
|
|
51
51
|
hexkit[s3]
|
|
52
|
-
opentelemetry-instrumentation-botocore>=0.
|
|
52
|
+
opentelemetry-instrumentation-botocore>=0.65b0
|
|
53
53
|
|
|
54
54
|
[redis]
|
|
55
55
|
redis<8,>=7.1
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Copyright 2021 - 2026 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln
|
|
2
|
-
# for the German Human Genome-Phenome Archive (GHGA)
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
"""OpenTelemetry specific configuration code. This is gated behind the opentelemetry extra."""
|
|
16
|
-
|
|
17
|
-
import logging
|
|
18
|
-
import os
|
|
19
|
-
from typing import Annotated
|
|
20
|
-
|
|
21
|
-
from opentelemetry import trace
|
|
22
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
23
|
-
from opentelemetry.sdk.environment_variables import OTEL_SDK_DISABLED
|
|
24
|
-
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
25
|
-
from opentelemetry.sdk.trace import TracerProvider
|
|
26
|
-
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
27
|
-
from opentelemetry.sdk.trace.sampling import ParentBasedTraceIdRatio
|
|
28
|
-
from pydantic import Field
|
|
29
|
-
from pydantic_settings import BaseSettings
|
|
30
|
-
|
|
31
|
-
logger = logging.getLogger(__name__)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class OpenTelemetryConfig(BaseSettings):
|
|
35
|
-
"""OpenTelemetry specific configuration options"""
|
|
36
|
-
|
|
37
|
-
enable_opentelemetry: bool = Field(
|
|
38
|
-
default=False,
|
|
39
|
-
description="If set to true, this will run necessary setup code."
|
|
40
|
-
"If set to false, environment variables are set that should also effectively "
|
|
41
|
-
"disable autoinstrumentation.",
|
|
42
|
-
)
|
|
43
|
-
otel_trace_sampling_rate: Annotated[float, Field(strict=True, ge=0, le=1)] = Field(
|
|
44
|
-
default=1.0,
|
|
45
|
-
description="Determines which proportion of spans should be sampled. "
|
|
46
|
-
"A value of 1.0 means all and is equivalent to the previous behaviour. "
|
|
47
|
-
"Setting this to 0 will result in no spans being sampled, but this does not "
|
|
48
|
-
"automatically set `enable_opentelemetry` to False.",
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def configure_opentelemetry(*, service_name: str, config: OpenTelemetryConfig):
|
|
53
|
-
"""Configure all needed parts of OpenTelemetry.
|
|
54
|
-
|
|
55
|
-
Setup of the TracerProvider is done programmatically, while disabling OpenTelemetry
|
|
56
|
-
sets the corresponding environment variable.
|
|
57
|
-
"""
|
|
58
|
-
if config.enable_opentelemetry:
|
|
59
|
-
resource = Resource(attributes={SERVICE_NAME: service_name})
|
|
60
|
-
# Replace the default static sampler with a probabilistic one that honors parent
|
|
61
|
-
# span sampling decisions
|
|
62
|
-
# This should consistently yield full traces within a service but not necessarily
|
|
63
|
-
# across service boundaries
|
|
64
|
-
# With the default sampling rate, behaviour does not change, but this allows to
|
|
65
|
-
# introduce head sampling by adjusting a config option on the service side later on
|
|
66
|
-
sampler = ParentBasedTraceIdRatio(rate=config.otel_trace_sampling_rate)
|
|
67
|
-
|
|
68
|
-
# Initialize service specific TracerProvider
|
|
69
|
-
trace_provider = TracerProvider(resource=resource, sampler=sampler)
|
|
70
|
-
processor = BatchSpanProcessor(OTLPSpanExporter())
|
|
71
|
-
trace_provider.add_span_processor(processor)
|
|
72
|
-
trace.set_tracer_provider(trace_provider)
|
|
73
|
-
else:
|
|
74
|
-
# Currently OTEL_SDK_DISABLED doesn't seem to be honored by all implementations yet
|
|
75
|
-
# It seems to be working well enough for the Python implementation.
|
|
76
|
-
os.environ[OTEL_SDK_DISABLED] = "true"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|