ondemand-obs 0.1.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.
- ondemand_obs-0.1.0/PKG-INFO +51 -0
- ondemand_obs-0.1.0/README.md +26 -0
- ondemand_obs-0.1.0/ondemand_obs/__init__.py +73 -0
- ondemand_obs-0.1.0/ondemand_obs/config.py +12 -0
- ondemand_obs-0.1.0/ondemand_obs/instruments.py +13 -0
- ondemand_obs-0.1.0/ondemand_obs/logs.py +23 -0
- ondemand_obs-0.1.0/ondemand_obs/metrics.py +13 -0
- ondemand_obs-0.1.0/ondemand_obs/temporal.py +13 -0
- ondemand_obs-0.1.0/ondemand_obs/traces.py +13 -0
- ondemand_obs-0.1.0/ondemand_obs.egg-info/PKG-INFO +51 -0
- ondemand_obs-0.1.0/ondemand_obs.egg-info/SOURCES.txt +15 -0
- ondemand_obs-0.1.0/ondemand_obs.egg-info/dependency_links.txt +1 -0
- ondemand_obs-0.1.0/ondemand_obs.egg-info/requires.txt +12 -0
- ondemand_obs-0.1.0/ondemand_obs.egg-info/top_level.txt +1 -0
- ondemand_obs-0.1.0/pyproject.toml +39 -0
- ondemand_obs-0.1.0/setup.cfg +4 -0
- ondemand_obs-0.1.0/tests/test_configure.py +38 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ondemand-obs
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenTelemetry observability layer for the Ondemand platform
|
|
5
|
+
Author-email: Ondemand AI <dev@ondemand-ai.com.br>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://ondemand-ai.com.br
|
|
8
|
+
Project-URL: Repository, https://github.com/Ondemand-AI/ondemand-obs
|
|
9
|
+
Keywords: opentelemetry,observability,tracing,ondemand
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: opentelemetry-api>=1.27
|
|
16
|
+
Requires-Dist: opentelemetry-sdk>=1.27
|
|
17
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27
|
|
18
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.48
|
|
19
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.48
|
|
20
|
+
Provides-Extra: temporal
|
|
21
|
+
Requires-Dist: temporalio>=1.7.0; extra == "temporal"
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
25
|
+
|
|
26
|
+
# ondemand-obs
|
|
27
|
+
|
|
28
|
+
OpenTelemetry observability layer for the [Ondemand AI](https://ondemand-ai.com.br) platform. Ships traces, metrics, and logs to HyperDX (or any OTLP-compatible backend).
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
Set `HYPERDX_API_KEY` in your environment. That's it — the `ondemand-ai[worker]` SDK calls `configure_observability()` automatically at worker startup.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
HYPERDX_API_KEY=your-key OTEL_SERVICE_NAME=my-robot python -m src.main
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install ondemand-obs # base (traces, metrics, logs, httpx/requests auto-instrument)
|
|
42
|
+
pip install "ondemand-obs[temporal]" # + Temporal TracingInterceptor
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Environment variables
|
|
46
|
+
|
|
47
|
+
| Variable | Required | Default |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `HYPERDX_API_KEY` | Yes (disables if absent) | — |
|
|
50
|
+
| `OTEL_SERVICE_NAME` | No | passed to `configure_observability()` |
|
|
51
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | No | `https://in-otel.hyperdx.io` |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ondemand-obs
|
|
2
|
+
|
|
3
|
+
OpenTelemetry observability layer for the [Ondemand AI](https://ondemand-ai.com.br) platform. Ships traces, metrics, and logs to HyperDX (or any OTLP-compatible backend).
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Set `HYPERDX_API_KEY` in your environment. That's it — the `ondemand-ai[worker]` SDK calls `configure_observability()` automatically at worker startup.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
HYPERDX_API_KEY=your-key OTEL_SERVICE_NAME=my-robot python -m src.main
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install ondemand-obs # base (traces, metrics, logs, httpx/requests auto-instrument)
|
|
17
|
+
pip install "ondemand-obs[temporal]" # + Temporal TracingInterceptor
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Environment variables
|
|
21
|
+
|
|
22
|
+
| Variable | Required | Default |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `HYPERDX_API_KEY` | Yes (disables if absent) | — |
|
|
25
|
+
| `OTEL_SERVICE_NAME` | No | passed to `configure_observability()` |
|
|
26
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | No | `https://in-otel.hyperdx.io` |
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ondemand-obs — OpenTelemetry observability for the Ondemand platform.
|
|
3
|
+
|
|
4
|
+
Usage in workers (automatic via ondemand-python SDK — no direct call needed):
|
|
5
|
+
|
|
6
|
+
from ondemand_obs import configure_observability
|
|
7
|
+
configure_observability("my-robot")
|
|
8
|
+
|
|
9
|
+
Set HYPERDX_API_KEY in env to enable. No-op if the key is absent.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
import os
|
|
14
|
+
import threading
|
|
15
|
+
|
|
16
|
+
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
|
|
17
|
+
|
|
18
|
+
from .config import ObsConfig
|
|
19
|
+
from .traces import setup_traces
|
|
20
|
+
from .metrics import setup_metrics
|
|
21
|
+
from .logs import setup_logs
|
|
22
|
+
from .instruments import setup_instruments
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger("ondemand_obs")
|
|
25
|
+
|
|
26
|
+
_configured = False
|
|
27
|
+
_lock = threading.Lock()
|
|
28
|
+
_log_handler = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def configure_observability(service_name: str, config: ObsConfig | None = None) -> None:
|
|
32
|
+
global _configured, _log_handler
|
|
33
|
+
|
|
34
|
+
if config is None:
|
|
35
|
+
config = ObsConfig()
|
|
36
|
+
|
|
37
|
+
if not config.api_key:
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
with _lock:
|
|
41
|
+
if _configured:
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
resource = Resource.create({
|
|
45
|
+
SERVICE_NAME: os.environ.get("OTEL_SERVICE_NAME", service_name),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
headers = {"authorization": config.api_key}
|
|
49
|
+
|
|
50
|
+
setup_traces(config.endpoint, headers, resource)
|
|
51
|
+
setup_metrics(config.endpoint, headers, resource)
|
|
52
|
+
_, handler = setup_logs(config.endpoint, headers, resource)
|
|
53
|
+
setup_instruments()
|
|
54
|
+
|
|
55
|
+
_log_handler = handler
|
|
56
|
+
_configured = True
|
|
57
|
+
|
|
58
|
+
logger.info(f"ondemand-obs: observability enabled for service '{service_name}'")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def is_configured() -> bool:
|
|
62
|
+
return _configured
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_otlp_log_handler() -> logging.Handler | None:
|
|
66
|
+
"""Return the OTLP LoggingHandler, or None if not configured."""
|
|
67
|
+
return _log_handler
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_temporal_tracing_interceptor():
|
|
71
|
+
"""Return a Temporal TracingInterceptor. Requires ondemand-obs[temporal]."""
|
|
72
|
+
from .temporal import get_tracing_interceptor
|
|
73
|
+
return get_tracing_interceptor()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
|
|
4
|
+
HYPERDX_OTLP_ENDPOINT = "https://in-otel.hyperdx.io"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ObsConfig:
|
|
9
|
+
endpoint: str = field(default_factory=lambda: os.environ.get(
|
|
10
|
+
"OTEL_EXPORTER_OTLP_ENDPOINT", HYPERDX_OTLP_ENDPOINT
|
|
11
|
+
))
|
|
12
|
+
api_key: str = field(default_factory=lambda: os.environ.get("HYPERDX_API_KEY", ""))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
def setup_instruments() -> None:
|
|
2
|
+
"""Register auto-instrumentation for common HTTP clients."""
|
|
3
|
+
try:
|
|
4
|
+
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
|
|
5
|
+
HTTPXClientInstrumentor().instrument()
|
|
6
|
+
except ImportError:
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
|
11
|
+
RequestsInstrumentor().instrument()
|
|
12
|
+
except ImportError:
|
|
13
|
+
pass
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from opentelemetry._logs import set_logger_provider
|
|
4
|
+
from opentelemetry.sdk._logs import LoggerProvider
|
|
5
|
+
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
|
|
6
|
+
from opentelemetry.sdk.resources import Resource
|
|
7
|
+
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
|
|
8
|
+
|
|
9
|
+
# LoggingHandler bridges Python's logging module → OTel log records → OTLP exporter
|
|
10
|
+
try:
|
|
11
|
+
from opentelemetry.sdk._logs import LoggingHandler
|
|
12
|
+
except ImportError:
|
|
13
|
+
# opentelemetry-sdk >= 1.28 may move this; fall back gracefully
|
|
14
|
+
from opentelemetry.sdk.logs import LoggingHandler # type: ignore[no-redef]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def setup_logs(endpoint: str, headers: dict, resource: Resource) -> tuple:
|
|
18
|
+
exporter = OTLPLogExporter(endpoint=f"{endpoint}/v1/logs", headers=headers)
|
|
19
|
+
provider = LoggerProvider(resource=resource)
|
|
20
|
+
provider.add_log_record_processor(BatchLogRecordProcessor(exporter))
|
|
21
|
+
set_logger_provider(provider)
|
|
22
|
+
handler = LoggingHandler(level=logging.NOTSET, logger_provider=provider)
|
|
23
|
+
return provider, handler
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from opentelemetry import metrics
|
|
2
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
|
3
|
+
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
|
|
4
|
+
from opentelemetry.sdk.resources import Resource
|
|
5
|
+
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def setup_metrics(endpoint: str, headers: dict, resource: Resource) -> MeterProvider:
|
|
9
|
+
exporter = OTLPMetricExporter(endpoint=f"{endpoint}/v1/metrics", headers=headers)
|
|
10
|
+
reader = PeriodicExportingMetricReader(exporter, export_interval_millis=60_000)
|
|
11
|
+
provider = MeterProvider(resource=resource, metric_readers=[reader])
|
|
12
|
+
metrics.set_meter_provider(provider)
|
|
13
|
+
return provider
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
def get_tracing_interceptor():
|
|
2
|
+
"""
|
|
3
|
+
Return a Temporal TracingInterceptor wired to the active OTel tracer provider.
|
|
4
|
+
Requires ondemand-obs[temporal] (temporalio>=1.7).
|
|
5
|
+
"""
|
|
6
|
+
try:
|
|
7
|
+
from temporalio.contrib.opentelemetry import TracingInterceptor
|
|
8
|
+
except ImportError as e:
|
|
9
|
+
raise ImportError(
|
|
10
|
+
"temporalio is required for Temporal tracing. "
|
|
11
|
+
"Install ondemand-obs[temporal] or ondemand-ai[worker]."
|
|
12
|
+
) from e
|
|
13
|
+
return TracingInterceptor()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from opentelemetry import trace
|
|
2
|
+
from opentelemetry.sdk.resources import Resource
|
|
3
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
4
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
5
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def setup_traces(endpoint: str, headers: dict, resource: Resource) -> TracerProvider:
|
|
9
|
+
exporter = OTLPSpanExporter(endpoint=f"{endpoint}/v1/traces", headers=headers)
|
|
10
|
+
provider = TracerProvider(resource=resource)
|
|
11
|
+
provider.add_span_processor(BatchSpanProcessor(exporter))
|
|
12
|
+
trace.set_tracer_provider(provider)
|
|
13
|
+
return provider
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ondemand-obs
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenTelemetry observability layer for the Ondemand platform
|
|
5
|
+
Author-email: Ondemand AI <dev@ondemand-ai.com.br>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://ondemand-ai.com.br
|
|
8
|
+
Project-URL: Repository, https://github.com/Ondemand-AI/ondemand-obs
|
|
9
|
+
Keywords: opentelemetry,observability,tracing,ondemand
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: opentelemetry-api>=1.27
|
|
16
|
+
Requires-Dist: opentelemetry-sdk>=1.27
|
|
17
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27
|
|
18
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.48
|
|
19
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.48
|
|
20
|
+
Provides-Extra: temporal
|
|
21
|
+
Requires-Dist: temporalio>=1.7.0; extra == "temporal"
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
25
|
+
|
|
26
|
+
# ondemand-obs
|
|
27
|
+
|
|
28
|
+
OpenTelemetry observability layer for the [Ondemand AI](https://ondemand-ai.com.br) platform. Ships traces, metrics, and logs to HyperDX (or any OTLP-compatible backend).
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
Set `HYPERDX_API_KEY` in your environment. That's it — the `ondemand-ai[worker]` SDK calls `configure_observability()` automatically at worker startup.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
HYPERDX_API_KEY=your-key OTEL_SERVICE_NAME=my-robot python -m src.main
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install ondemand-obs # base (traces, metrics, logs, httpx/requests auto-instrument)
|
|
42
|
+
pip install "ondemand-obs[temporal]" # + Temporal TracingInterceptor
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Environment variables
|
|
46
|
+
|
|
47
|
+
| Variable | Required | Default |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `HYPERDX_API_KEY` | Yes (disables if absent) | — |
|
|
50
|
+
| `OTEL_SERVICE_NAME` | No | passed to `configure_observability()` |
|
|
51
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | No | `https://in-otel.hyperdx.io` |
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
ondemand_obs/__init__.py
|
|
4
|
+
ondemand_obs/config.py
|
|
5
|
+
ondemand_obs/instruments.py
|
|
6
|
+
ondemand_obs/logs.py
|
|
7
|
+
ondemand_obs/metrics.py
|
|
8
|
+
ondemand_obs/temporal.py
|
|
9
|
+
ondemand_obs/traces.py
|
|
10
|
+
ondemand_obs.egg-info/PKG-INFO
|
|
11
|
+
ondemand_obs.egg-info/SOURCES.txt
|
|
12
|
+
ondemand_obs.egg-info/dependency_links.txt
|
|
13
|
+
ondemand_obs.egg-info/requires.txt
|
|
14
|
+
ondemand_obs.egg-info/top_level.txt
|
|
15
|
+
tests/test_configure.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
opentelemetry-api>=1.27
|
|
2
|
+
opentelemetry-sdk>=1.27
|
|
3
|
+
opentelemetry-exporter-otlp-proto-http>=1.27
|
|
4
|
+
opentelemetry-instrumentation-httpx>=0.48
|
|
5
|
+
opentelemetry-instrumentation-requests>=0.48
|
|
6
|
+
|
|
7
|
+
[dev]
|
|
8
|
+
pytest>=8.0
|
|
9
|
+
pytest-asyncio>=0.23
|
|
10
|
+
|
|
11
|
+
[temporal]
|
|
12
|
+
temporalio>=1.7.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ondemand_obs
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ondemand-obs"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "OpenTelemetry observability layer for the Ondemand platform"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "Apache-2.0"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Ondemand AI", email = "dev@ondemand-ai.com.br"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["opentelemetry", "observability", "tracing", "ondemand"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"License :: OSI Approved :: Apache Software License",
|
|
19
|
+
"Topic :: Software Development :: Libraries",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
dependencies = [
|
|
23
|
+
"opentelemetry-api>=1.27",
|
|
24
|
+
"opentelemetry-sdk>=1.27",
|
|
25
|
+
"opentelemetry-exporter-otlp-proto-http>=1.27",
|
|
26
|
+
"opentelemetry-instrumentation-httpx>=0.48",
|
|
27
|
+
"opentelemetry-instrumentation-requests>=0.48",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
temporal = ["temporalio>=1.7.0"]
|
|
32
|
+
dev = ["pytest>=8.0", "pytest-asyncio>=0.23"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://ondemand-ai.com.br"
|
|
36
|
+
Repository = "https://github.com/Ondemand-AI/ondemand-obs"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
include = ["ondemand_obs*"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _reload_module():
|
|
7
|
+
"""Reload ondemand_obs to reset global state between tests."""
|
|
8
|
+
for mod in list(sys.modules.keys()):
|
|
9
|
+
if mod.startswith("ondemand_obs"):
|
|
10
|
+
del sys.modules[mod]
|
|
11
|
+
import ondemand_obs
|
|
12
|
+
return ondemand_obs
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_noop_without_api_key(monkeypatch):
|
|
16
|
+
monkeypatch.delenv("HYPERDX_API_KEY", raising=False)
|
|
17
|
+
obs = _reload_module()
|
|
18
|
+
obs.configure_observability("test-service")
|
|
19
|
+
assert not obs.is_configured()
|
|
20
|
+
assert obs.get_otlp_log_handler() is None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_idempotent(monkeypatch):
|
|
24
|
+
monkeypatch.setenv("HYPERDX_API_KEY", "test-key-123")
|
|
25
|
+
obs = _reload_module()
|
|
26
|
+
obs.configure_observability("svc-a")
|
|
27
|
+
obs.configure_observability("svc-b") # second call should be no-op
|
|
28
|
+
assert obs.is_configured()
|
|
29
|
+
# If second call ran, it would raise because providers are already set.
|
|
30
|
+
# Reaching here means idempotency guard worked.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_configured_with_key(monkeypatch):
|
|
34
|
+
monkeypatch.setenv("HYPERDX_API_KEY", "test-key-456")
|
|
35
|
+
obs = _reload_module()
|
|
36
|
+
obs.configure_observability("my-robot")
|
|
37
|
+
assert obs.is_configured()
|
|
38
|
+
assert obs.get_otlp_log_handler() is not None
|