Skip to content

Commit 2c37ddd

Browse files
committed
Set DSTACK_OTEL_METRICS_EXPORTERS=otlp by default
1 parent b2459c7 commit 2c37ddd

6 files changed

Lines changed: 32 additions & 18 deletions

File tree

mkdocs/docs/guides/server-deployment.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -444,11 +444,14 @@ $ DSTACK_OTEL_TRACES_ENABLED=1 \
444444
- `DSTACK_OTEL_TRACES_BACKGROUND_SAMPLE_RATE` – The head sampling rate for background task traces.
445445

446446
??? info "Metrics exporters"
447-
By default, if the [Prometheus `/metrics` endpoint](../concepts/metrics.md) is enabled via
448-
`DSTACK_ENABLE_PROMETHEUS_METRICS`, OpenTelemetry metrics are exposed there alongside the built-in
449-
`dstack` metrics; otherwise they are pushed via OTLP. Set `DSTACK_OTEL_METRICS_EXPORTERS`
450-
to a comma-separated list of `prometheus` and/or `otlp` to override, e.g. force OTLP push
451-
even when `/metrics` is enabled.
447+
By default, metrics are pushed via OTLP like traces and logs. Set
448+
`DSTACK_OTEL_METRICS_EXPORTERS=prometheus` to instead expose them on the
449+
[Prometheus `/metrics` endpoint](../concepts/metrics.md) alongside the built-in `dstack`
450+
metrics (a comma-separated list enables both exporters at once).
451+
452+
If you run multiple server replicas, only use the `prometheus` exporter if Prometheus
453+
scrapes each replica directly. Scraping through a load balancer interleaves the
454+
replicas' counters into the same series and silently corrupts all rates.
452455

453456
## Encryption
454457

mkdocs/docs/reference/env.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ For more details on the options below, refer to the [server deployment](../guide
130130
- `DSTACK_OTEL_TRACES_BACKGROUND_SAMPLE_RATE`{ #DSTACK_OTEL_TRACES_BACKGROUND_SAMPLE_RATE } – The head sampling rate for background task traces. Defaults to `1.0`.
131131
- `DSTACK_OTEL_LOGS_ENABLED`{ #DSTACK_OTEL_LOGS_ENABLED } – Enables server log export via OTLP if set to any value. Requires the `otel` extra.
132132
- `DSTACK_OTEL_METRICS_ENABLED`{ #DSTACK_OTEL_METRICS_ENABLED } – Enables OpenTelemetry metrics if set to any value. Requires the `otel` extra.
133-
- `DSTACK_OTEL_METRICS_EXPORTERS`{ #DSTACK_OTEL_METRICS_EXPORTERS } – A comma-separated list of OpenTelemetry metrics exporters: `prometheus` (expose on the `/metrics` endpoint) and/or `otlp` (push via OTLP). Defaults to `prometheus` if `DSTACK_ENABLE_PROMETHEUS_METRICS` is set, otherwise `otlp`.
133+
- `DSTACK_OTEL_METRICS_EXPORTERS`{ #DSTACK_OTEL_METRICS_EXPORTERS } – A comma-separated list of OpenTelemetry metrics exporters: `otlp` (push via OTLP) and/or `prometheus` (expose on the `/metrics` endpoint). Defaults to `otlp`.
134134
- `DSTACK_DEFAULT_SERVICE_CLIENT_MAX_BODY_SIZE`{ #DSTACK_DEFAULT_SERVICE_CLIENT_MAX_BODY_SIZE } – Request body size limit for services running with a gateway, in bytes. Defaults to 64 MiB.
135135
- `DSTACK_SERVICE_CLIENT_TIMEOUT`{ #DSTACK_SERVICE_CLIENT_TIMEOUT } – Timeout in seconds for HTTP requests sent from the in-server proxy and gateways to service replicas. Defaults to 60.
136136
- `DSTACK_FORBID_SERVICES_WITHOUT_GATEWAY`{ #DSTACK_FORBID_SERVICES_WITHOUT_GATEWAY } – Forbids registering new services without a gateway if set to any value.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import uuid
2+
3+
SERVER_REPLICA_ID = str(uuid.uuid4())
4+
"""
5+
Unique ID of this server process, regenerated on every start.
6+
Distinguishes replicas in multi-replica deployments, e.g. in exported telemetry.
7+
"""

src/dstack/_internal/server/settings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@
136136
OTEL_METRICS_ENABLED = os.getenv("DSTACK_OTEL_METRICS_ENABLED") is not None
137137
"""Enables OpenTelemetry metrics. Requires the `otel` extra to be installed."""
138138
OTEL_METRICS_EXPORTERS = os.getenv("DSTACK_OTEL_METRICS_EXPORTERS")
139-
"""A comma-separated list of metrics exporters: `prometheus` (expose via the /metrics endpoint)
140-
and/or `otlp` (push via OTLP, configured by standard `OTEL_*` env vars).
141-
Defaults to `prometheus` if the /metrics endpoint is enabled, otherwise `otlp`.
139+
"""A comma-separated list of metrics exporters: `otlp` (push via OTLP, configured by
140+
standard `OTEL_*` env vars) and/or `prometheus` (expose via the /metrics endpoint).
141+
Defaults to `otlp`.
142142
"""
143143

144144
DEFAULT_CREDS_DISABLED = os.getenv("DSTACK_DEFAULT_CREDS_DISABLED") is not None

src/dstack/_internal/server/utils/otel/utils.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
from dstack._internal import settings as core_settings
3939
from dstack._internal.server import settings
40+
from dstack._internal.server.identity import SERVER_REPLICA_ID
4041
from dstack._internal.server.utils.common import is_background_task_name
4142
from dstack._internal.server.utils.logging import AsyncioCancelledErrorFilter
4243
from dstack._internal.utils.logging import get_logger
@@ -110,10 +111,12 @@ def _instrument(app: FastAPI, engine: AsyncEngine) -> None:
110111

111112

112113
def _get_metrics_exporters() -> List[str]:
114+
# OTLP by default, like traces and logs. The prometheus exporter (metrics on
115+
# the /metrics endpoint) is opt-in: scraping /metrics through a load
116+
# balancer with multiple server replicas interleaves the replicas' counters
117+
# into the same series, silently corrupting rates.
113118
if settings.OTEL_METRICS_EXPORTERS is not None:
114119
return [e.strip() for e in settings.OTEL_METRICS_EXPORTERS.split(",") if e.strip()]
115-
if settings.ENABLE_PROMETHEUS_METRICS:
116-
return ["prometheus"]
117120
return ["otlp"]
118121

119122

@@ -137,6 +140,9 @@ def _get_resource() -> Resource:
137140
return Resource.create(
138141
{
139142
"service.name": "dstack-server",
143+
# Distinguishes replicas: without it, metrics pushed by multiple
144+
# server replicas collapse into the same series, corrupting counters
145+
"service.instance.id": SERVER_REPLICA_ID,
140146
"service.version": core_settings.DSTACK_VERSION or "dev",
141147
"deployment.environment.name": settings.SERVER_ENVIRONMENT,
142148
}

src/tests/_internal/server/utils/test_tracing.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,17 @@ def test_does_not_export_otel_sdk_records(self):
148148

149149
class TestGetMetricsExporters:
150150
@pytest.mark.parametrize(
151-
("exporters", "prometheus_enabled", "expected"),
151+
("exporters", "expected"),
152152
[
153-
(None, True, ["prometheus"]),
154-
(None, False, ["otlp"]),
155-
("otlp", True, ["otlp"]),
156-
("prometheus, otlp", False, ["prometheus", "otlp"]),
153+
(None, ["otlp"]),
154+
("prometheus", ["prometheus"]),
155+
("prometheus, otlp", ["prometheus", "otlp"]),
157156
],
158157
)
159-
def test_returns_expected(self, monkeypatch, exporters, prometheus_enabled, expected):
158+
def test_returns_expected(self, monkeypatch, exporters, expected):
160159
from dstack._internal.server import settings
161160

162161
monkeypatch.setattr(settings, "OTEL_METRICS_EXPORTERS", exporters)
163-
monkeypatch.setattr(settings, "ENABLE_PROMETHEUS_METRICS", prometheus_enabled)
164162
assert _get_metrics_exporters() == expected
165163

166164

0 commit comments

Comments
 (0)