diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java index 58d6d13ad4..297457d89a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java @@ -16,6 +16,10 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace; +import java.util.Map; + +import io.micrometer.dynatrace.DynatraceApiVersion; + import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -24,39 +28,79 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * metrics export. * * @author Andy Wilkinson + * @author Georg Pirklbauer * @since 2.1.0 */ @ConfigurationProperties(prefix = "management.metrics.export.dynatrace") public class DynatraceProperties extends StepRegistryProperties { + /** + * The Dynatrace metrics API version that metrics should be sent to. Defaults to v1. + * Required to define which API is used for export. + */ + private DynatraceApiVersion apiVersion = DynatraceApiVersion.V1; + /** * Dynatrace authentication token. + * + * API v1: required, API v2: optional */ private String apiToken; /** * ID of the custom device that is exporting metrics to Dynatrace. + * + * API v1: required, API v2: not applicable (ignored) */ private String deviceId; /** * Technology type for exported metrics. Used to group metrics under a logical * technology name in the Dynatrace UI. + * + * API v1: required, API v2: not applicable (ignored) */ private String technologyType = "java"; /** * URI to ship metrics to. Should be used for SaaS, self managed instances or to * en-route through an internal proxy. + * + * API v1: required, API v2: optional */ private String uri; /** * Group for exported metrics. Used to specify custom device group name in the * Dynatrace UI. + * + * API v1: required, API v2: not applicable (ignored) */ private String group; + /** + * An optional prefix string that is added to all metrics exported. + * + * API v1: not applicable (ignored), API v2: optional + */ + private String metricKeyPrefix; + + /** + * An optional Boolean that allows enabling of the Dynatrace metadata export. On by + * default. + * + * API v1: not applicable (ignored), API v2: optional + */ + private Boolean enrichWithDynatraceMetadata = true; + + /** + * Optional default dimensions that are added to all metrics in the form of key-value + * pairs. These are overwritten by Micrometer tags if they use the same key. + * + * API v1: not applicable (ignored), API v2: optional + */ + private Map defaultDimensions; + public String getApiToken() { return this.apiToken; } @@ -97,4 +141,36 @@ public class DynatraceProperties extends StepRegistryProperties { this.group = group; } + public String getMetricKeyPrefix() { + return this.metricKeyPrefix; + } + + public void setMetricKeyPrefix(String metricKeyPrefix) { + this.metricKeyPrefix = metricKeyPrefix; + } + + public Boolean getEnrichWithDynatraceMetadata() { + return this.enrichWithDynatraceMetadata; + } + + public void setEnrichWithDynatraceMetadata(Boolean enrichWithDynatraceMetadata) { + this.enrichWithDynatraceMetadata = enrichWithDynatraceMetadata; + } + + public Map getDefaultDimensions() { + return this.defaultDimensions; + } + + public void setDefaultDimensions(Map defaultDimensions) { + this.defaultDimensions = defaultDimensions; + } + + public DynatraceApiVersion getApiVersion() { + return this.apiVersion; + } + + public void setApiVersion(DynatraceApiVersion apiVersion) { + this.apiVersion = apiVersion; + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java index 6d7444ce82..7e232ffe0e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java @@ -16,6 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace; +import java.util.Map; + +import io.micrometer.dynatrace.DynatraceApiVersion; import io.micrometer.dynatrace.DynatraceConfig; import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter; @@ -24,6 +27,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties. * Adapter to convert {@link DynatraceProperties} to a {@link DynatraceConfig}. * * @author Andy Wilkinson + * @author Georg Pirklbauer */ class DynatracePropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter implements DynatraceConfig { @@ -62,4 +66,24 @@ class DynatracePropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapt return get(DynatraceProperties::getGroup, DynatraceConfig.super::group); } + @Override + public DynatraceApiVersion apiVersion() { + return get(DynatraceProperties::getApiVersion, DynatraceConfig.super::apiVersion); + } + + @Override + public String metricKeyPrefix() { + return get(DynatraceProperties::getMetricKeyPrefix, DynatraceConfig.super::metricKeyPrefix); + } + + @Override + public Map defaultDimensions() { + return get(DynatraceProperties::getDefaultDimensions, DynatraceConfig.super::defaultDimensions); + } + + @Override + public boolean enrichWithDynatraceMetadata() { + return get(DynatraceProperties::getEnrichWithDynatraceMetadata, + DynatraceConfig.super::enrichWithDynatraceMetadata); + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java index 8a4b25b079..74aaa5e454 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java @@ -16,6 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace; +import java.util.HashMap; + +import io.micrometer.dynatrace.DynatraceApiVersion; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -24,6 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link DynatracePropertiesConfigAdapter}. * * @author Andy Wilkinson + * @author Georg Pirklbauer */ class DynatracePropertiesConfigAdapterTests { @@ -62,4 +66,54 @@ class DynatracePropertiesConfigAdapterTests { assertThat(new DynatracePropertiesConfigAdapter(properties).group()).isEqualTo("group-1"); } + @Test + void whenPropertiesApiVersionIsSetAdapterGroupReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + properties.setApiVersion(DynatraceApiVersion.V1); + assertThat(new DynatracePropertiesConfigAdapter(properties).apiVersion()).isSameAs(DynatraceApiVersion.V1); + } + + @Test + void whenPropertiesMetricKeyPrefixIsSetAdapterGroupReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + properties.setMetricKeyPrefix("my.prefix"); + assertThat(new DynatracePropertiesConfigAdapter(properties).metricKeyPrefix()).isEqualTo("my.prefix"); + } + + @Test + void whenPropertiesEnrichWithOneAgentMetadataIsSetAdapterGroupReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + properties.setEnrichWithDynatraceMetadata(true); + assertThat(new DynatracePropertiesConfigAdapter(properties).enrichWithDynatraceMetadata()).isTrue(); + } + + @Test + void whenPropertiesDefaultDimensionsIsSetAdapterGroupReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + HashMap defaultDimensions = new HashMap() { + { + put("dim1", "value1"); + put("dim2", "value2"); + } + }; + + properties.setDefaultDimensions(defaultDimensions); + assertThat(new DynatracePropertiesConfigAdapter(properties).defaultDimensions()) + .containsExactlyEntriesOf(defaultDimensions); + } + + @Test + void defaultValues() { + DynatraceProperties properties = new DynatraceProperties(); + assertThat(properties.getApiToken()).isNull(); + assertThat(properties.getDeviceId()).isNull(); + assertThat(properties.getTechnologyType()).isEqualTo("java"); + assertThat(properties.getUri()).isNull(); + assertThat(properties.getGroup()).isNull(); + assertThat(properties.getApiVersion()).isSameAs(DynatraceApiVersion.V1); + assertThat(properties.getMetricKeyPrefix()).isNull(); + assertThat(properties.getEnrichWithDynatraceMetadata()).isTrue(); + assertThat(properties.getDefaultDimensions()).isNull(); + } + } diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc index 5a942ac413..6187617337 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc @@ -147,8 +147,15 @@ You can also change the interval at which metrics are sent to Datadog: [[actuator.metrics.export.dynatrace]] ==== Dynatrace -Dynatrace registry pushes metrics to the configured URI periodically. -To export metrics to {micrometer-registry-docs}/dynatrace[Dynatrace], your API token, device ID, and URI must be provided: + +Dynatrace offers two metrics ingest APIs, both of which are implemented for {micrometer-registry-docs}/dynatrace[Micrometer]: + +[[actuator.metrics.export.dynatrace.api-v2]] +===== API v2 + +The API v2 can be used in two ways: + +If a local OneAgent is running on the host, it is enough to set the API version to v2 and metrics will be automatically exported to the https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/local-api/[local OneAgent ingest endpoint], which forwards them to the Dynatrace backend: [source,yaml,indent=0,subs="verbatim",configprops,configblocks] ---- @@ -156,12 +163,74 @@ To export metrics to {micrometer-registry-docs}/dynatrace[Dynatrace], your API t metrics: export: dynatrace: - api-token: "YOUR_TOKEN" - device-id: "YOUR_DEVICE_ID" - uri: "YOUR_URI" + api-version: "v2" ---- -You can also change the interval at which metrics are sent to Dynatrace: +If no local OneAgent is running, the endpoint of the https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v2/post-ingest-metrics/[Metrics API v2] and an API token are required. +The https://www.dynatrace.com/support/help/dynatrace-api/basics/dynatrace-api-authentication/[API token] must have the "Ingest metrics" (`metrics.ingest`) permission set. +It is recommended to limit scope to only this one permission. +Please ensure that the endpoint URI contains the path (e.g. `/api/v2/metrics/ingest`). + +[source,yaml,indent=0,subs="verbatim",configprops,configblocks] +---- + management: + metrics: + export: + dynatrace: + api-version: "v2" + # uri: "https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest" for managed deployments. + uri: "https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest" + api-token: "YOUR_TOKEN" # should be read from a secure source and not hard-coded. +---- + +When using the Dynatrace v2 API, the following optional features are available: + +* Metric key prefix: Sets a prefix that will be prepended to all exported metric keys. +* Enrich with Dynatrace metadata: If a OneAgent or Dynatrace operator is running, enrich metrics with additional metadata (e.g. about the host, process or pod). +* Default dimensions: Specify key-value pairs that are added to all exported metrics. +If tags with the same key are specified using Micrometer, they overwrite the default dimensions. + +[source,yaml,indent=0,subs="verbatim",configprops,configblocks] +---- + management: + metrics: + export: + dynatrace: + # specify token and uri or leave blank for OneAgent export + api-version: "v2" + metric-key-prefix: "your.key.prefix" + enrich-with-dynatrace-metadata: true + default-dimensions: + key1: "value1" + key2: "value2" +---- + +[[actuator.metrics.export.dynatrace.api-v1]] +===== API v1 (Legacy) + +The Dynatrace API v1 registry pushes metrics to the configured URI periodically using the https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v1/[Timeseries API v1]. +For backwards-compatibility with existing setups, `api-version` defaults to `"v1"` but can also be specified explicitly as such. +To export metrics to {micrometer-registry-docs}/dynatrace[Dynatrace], your API token, device ID, and URI must be provided: +For the API v1, the base environment URI needs to be specified, without any path. +The API v1 endpoint path will be added automatically. + +[source,yaml,indent=0,subs="verbatim",configprops,configblocks] +---- + management: + metrics: + export: + dynatrace: + device-id: "YOUR_DEVICE_ID" + # uri: "https://{your-domain}/e/{your-environment-id}" on managed deployments. + uri: "https://{your-environment-id}.live.dynatrace.com" + api-token: "YOUR_TOKEN" # should be read from a secure property source +---- + +[[actuator.metrics.export.dynatrace.version-independent-settings]] +===== Version-independent settings + +You can also change the interval at which metrics are sent to Dynatrace (works for both API versions). +The default export interval is `60s`. [source,yaml,indent=0,subs="verbatim",configprops,configblocks] ---- @@ -172,7 +241,7 @@ You can also change the interval at which metrics are sent to Dynatrace: step: "30s" ---- - +More information on how to set up the Dynatrace exporter for Micrometer can be found in {micrometer-registry-docs}/dynatrace[the Micrometer documentation]. [[actuator.metrics.export.elastic]] ==== Elastic