Skip to content

Commit e34c2fd

Browse files
authored
Add support for otel.java.metrics.cardinality.limit system property (#10541)
Add support for 'otel.java.metrics.cardinality.limit' system property Add OTel/DD cardinality limit config keys Co-authored-by: stuart.mcculloch <stuart.mcculloch@datadoghq.com>
1 parent 1e93c87 commit e34c2fd

File tree

6 files changed

+49
-6
lines changed

6 files changed

+49
-6
lines changed

dd-java-agent/agent-otel/otel-shim/src/main/java/datadog/opentelemetry/shim/metrics/data/OtelMetricStorage.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public final class OtelMetricStorage {
2323
private static final RatelimitedLogger RATELIMITED_LOGGER =
2424
new RatelimitedLogger(LOGGER, 5, TimeUnit.MINUTES);
2525

26-
private static final int DEFAULT_MAX_CARDINALITY = 2_000;
26+
private static final int CARDINALITY_LIMIT = Config.get().getMetricsOtelCardinalityLimit();
2727

2828
private static final Attributes CARDINALITY_OVERFLOW =
2929
Attributes.builder().put("otel.metric.overflow", true).build();
@@ -102,11 +102,11 @@ private OtelAggregator aggregator(
102102
if (null != aggregator) {
103103
return aggregator;
104104
}
105-
if (aggregators.size() >= DEFAULT_MAX_CARDINALITY) {
105+
if (aggregators.size() >= CARDINALITY_LIMIT) {
106106
RATELIMITED_LOGGER.warn(
107107
"Instrument {} has exceeded the maximum allowed cardinality ({}).",
108108
descriptor.getName(),
109-
DEFAULT_MAX_CARDINALITY);
109+
CARDINALITY_LIMIT);
110110
attributes = CARDINALITY_OVERFLOW; // write data to overflow
111111
}
112112
return aggregators.computeIfAbsent(attributes, aggregatorSupplier);
@@ -153,7 +153,7 @@ private void doCollectAndReset(OtelInstrumentVisitor visitor) {
153153
Map<Attributes, OtelAggregator> aggregators = recording.aggregators;
154154

155155
// avoid churn: only remove empty aggregators if we're over cardinality
156-
if (aggregators.size() >= DEFAULT_MAX_CARDINALITY) {
156+
if (aggregators.size() >= CARDINALITY_LIMIT) {
157157
aggregators.values().removeIf(OtelAggregator::isEmpty);
158158
}
159159

dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,10 @@ public final class ConfigDefaults {
104104

105105
public static final boolean DEFAULT_METRICS_OTEL_ENABLED = false;
106106
// Default recommended by Datadog; it differs from Otel’s default of 60000 (60s)
107-
static final int DEFAULT_METRICS_OTEL_INTERVAL = 10000; // ms
107+
static final int DEFAULT_METRICS_OTEL_INTERVAL = 10_000; // ms
108108
// Default recommended by Datadog; it differs from Otel’s default of 30000 (30s)
109-
static final int DEFAULT_METRICS_OTEL_TIMEOUT = 7500; // ms
109+
static final int DEFAULT_METRICS_OTEL_TIMEOUT = 7_500; // ms
110+
static final int DEFAULT_METRICS_OTEL_CARDINALITY_LIMIT = 2_000;
110111

111112
static final String DEFAULT_OTLP_HTTP_METRIC_ENDPOINT = "v1/metrics";
112113
static final String DEFAULT_OTLP_HTTP_PORT = "4318";

dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public final class OtlpConfig {
55
public static final String METRICS_OTEL_ENABLED = "metrics.otel.enabled";
66
public static final String METRICS_OTEL_INTERVAL = "metrics.otel.interval";
77
public static final String METRICS_OTEL_TIMEOUT = "metrics.otel.timeout";
8+
public static final String METRICS_OTEL_CARDINALITY_LIMIT = "metrics.otel.cardinality.limit";
89

910
public static final String OTLP_METRICS_ENDPOINT = "otlp.metrics.endpoint";
1011
public static final String OTLP_METRICS_HEADERS = "otlp.metrics.headers";

internal-api/src/main/java/datadog/trace/api/Config.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT;
112112
import static datadog.trace.api.ConfigDefaults.DEFAULT_LLM_OBS_AGENTLESS_ENABLED;
113113
import static datadog.trace.api.ConfigDefaults.DEFAULT_LOGS_INJECTION_ENABLED;
114+
import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_CARDINALITY_LIMIT;
114115
import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_ENABLED;
115116
import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_INTERVAL;
116117
import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_TIMEOUT;
@@ -444,6 +445,7 @@
444445
import static datadog.trace.api.config.JmxFetchConfig.JMX_TAGS;
445446
import static datadog.trace.api.config.LlmObsConfig.LLMOBS_AGENTLESS_ENABLED;
446447
import static datadog.trace.api.config.LlmObsConfig.LLMOBS_ML_APP;
448+
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_CARDINALITY_LIMIT;
447449
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED;
448450
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL;
449451
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT;
@@ -913,6 +915,7 @@ public static String getHostName() {
913915
private final boolean metricsOtelEnabled;
914916
private final int metricsOtelInterval;
915917
private final int metricsOtelTimeout;
918+
private final int metricsOtelCardinalityLimit;
916919
private final String otlpMetricsEndpoint;
917920
private final Map<String, String> otlpMetricsHeaders;
918921
private final OtlpConfig.Protocol otlpMetricsProtocol;
@@ -1887,6 +1890,17 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins
18871890
metricsOtelEnabled =
18881891
configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED);
18891892

1893+
int cardinalityLimit =
1894+
configProvider.getInteger(
1895+
METRICS_OTEL_CARDINALITY_LIMIT, DEFAULT_METRICS_OTEL_CARDINALITY_LIMIT);
1896+
if (cardinalityLimit < 0) {
1897+
log.warn(
1898+
"Invalid OTel metrics cardinality limit: {}. The value must be positive",
1899+
cardinalityLimit);
1900+
cardinalityLimit = DEFAULT_METRICS_OTEL_CARDINALITY_LIMIT;
1901+
}
1902+
metricsOtelCardinalityLimit = cardinalityLimit;
1903+
18901904
int otelInterval =
18911905
configProvider.getInteger(METRICS_OTEL_INTERVAL, DEFAULT_METRICS_OTEL_INTERVAL);
18921906
if (otelInterval < 0) {
@@ -5189,6 +5203,10 @@ public boolean isMetricsOtelEnabled() {
51895203
return metricsOtelEnabled;
51905204
}
51915205

5206+
public int getMetricsOtelCardinalityLimit() {
5207+
return metricsOtelCardinalityLimit;
5208+
}
5209+
51925210
public int getMetricsOtelInterval() {
51935211
return metricsOtelInterval;
51945212
}
@@ -6232,6 +6250,8 @@ public String toString() {
62326250
+ metricsOtelInterval
62336251
+ ", metricsOtelTimeout="
62346252
+ metricsOtelTimeout
6253+
+ ", metricsOtelCardinalityLimit="
6254+
+ metricsOtelCardinalityLimit
62356255
+ ", otlpMetricsEndpoint="
62366256
+ otlpMetricsEndpoint
62376257
+ ", otlpMetricsHeaders="

metadata/supported-configurations.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,14 @@
22652265
"aliases": []
22662266
}
22672267
],
2268+
"DD_METRICS_OTEL_CARDINALITY_LIMIT": [
2269+
{
2270+
"version": "A",
2271+
"type": "int",
2272+
"default": "2000",
2273+
"aliases": []
2274+
}
2275+
],
22682276
"DD_OBFUSCATION_QUERY_STRING_REGEXP": [
22692277
{
22702278
"version": "A",
@@ -11096,6 +11104,14 @@
1109611104
"default": null,
1109711105
"aliases": []
1109811106
}
11107+
],
11108+
"OTEL_JAVA_METRICS_CARDINALITY_LIMIT": [
11109+
{
11110+
"version": "A",
11111+
"type": "int",
11112+
"default": "2000",
11113+
"aliases": []
11114+
}
1109911115
]
1110011116
},
1110111117
"deprecations": {}

utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static datadog.trace.api.config.GeneralConfig.SERVICE_NAME;
99
import static datadog.trace.api.config.GeneralConfig.TAGS;
1010
import static datadog.trace.api.config.GeneralConfig.VERSION;
11+
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_CARDINALITY_LIMIT;
1112
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED;
1213
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL;
1314
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT;
@@ -144,6 +145,10 @@ private void setupMetricsOtelEnvironment() {
144145
capture(
145146
METRICS_OTEL_TIMEOUT,
146147
getOtelProperty("otel.metric.export.timeout", "dd." + METRICS_OTEL_TIMEOUT));
148+
capture(
149+
METRICS_OTEL_CARDINALITY_LIMIT,
150+
getOtelProperty(
151+
"otel.java.metrics.cardinality.limit", "dd." + METRICS_OTEL_CARDINALITY_LIMIT));
147152

148153
String exporter = getOtelProperty("otel.metrics.exporter");
149154
if (exporter == null || "otlp".equalsIgnoreCase(exporter)) {

0 commit comments

Comments
 (0)