-
Notifications
You must be signed in to change notification settings - Fork 30
switch alternative approach to declarative config #1060
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
31ee949
8f71a1d
ac32eef
c4442e4
ca2f395
84ba230
f640cf2
70347a9
2988b38
6ec4d45
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,9 +29,6 @@ | |
| import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalInstrumentationModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationPropertyModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; | ||
|
|
@@ -61,49 +58,16 @@ | |
| public class ElasticDeclarativeConfigurationCustomizer | ||
| implements DeclarativeConfigurationCustomizerProvider { | ||
|
|
||
| private static final String RUNTIME_TELEMETRY = "runtime_telemetry"; | ||
| private static final String EMIT_EXPERIMENTAL_METRICS_DEVELOPMENT = | ||
| "emit_experimental_metrics/development"; | ||
|
|
||
| @Override | ||
| public void customize(DeclarativeConfigurationCustomizer customizer) { | ||
| customizer.addModelCustomizer( | ||
| model -> { | ||
| customizeResources(model); | ||
| customizeUserAgent(model); | ||
| customizeExperimentalRuntimeTelemetryMetrics(model); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] we remove the "magic" implementation, this is replaced with the default config in yaml (unfortunately we don't have a test for it, at least yet). |
||
| return model; | ||
| }); | ||
| } | ||
|
|
||
| private static void customizeExperimentalRuntimeTelemetryMetrics( | ||
| OpenTelemetryConfigurationModel model) { | ||
|
|
||
| ExperimentalInstrumentationModel instrumentationDevelopment = | ||
| model.getInstrumentationDevelopment(); | ||
| if (instrumentationDevelopment == null) { | ||
| instrumentationDevelopment = new ExperimentalInstrumentationModel(); | ||
| model.withInstrumentationDevelopment(instrumentationDevelopment); | ||
| } | ||
|
|
||
| ExperimentalLanguageSpecificInstrumentationModel java = instrumentationDevelopment.getJava(); | ||
| if (java == null) { | ||
| java = new ExperimentalLanguageSpecificInstrumentationModel(); | ||
| instrumentationDevelopment.withJava(java); | ||
| } | ||
|
|
||
| ExperimentalLanguageSpecificInstrumentationPropertyModel runtimeTelemetry = | ||
| java.getAdditionalProperties().get(RUNTIME_TELEMETRY); | ||
| if (runtimeTelemetry == null) { | ||
| runtimeTelemetry = new ExperimentalLanguageSpecificInstrumentationPropertyModel(); | ||
| java.withAdditionalProperty(RUNTIME_TELEMETRY, runtimeTelemetry); | ||
| } | ||
| if (runtimeTelemetry.getAdditionalProperties().get(EMIT_EXPERIMENTAL_METRICS_DEVELOPMENT) | ||
| == null) { | ||
| runtimeTelemetry.withAdditionalProperty(EMIT_EXPERIMENTAL_METRICS_DEVELOPMENT, true); | ||
| } | ||
| } | ||
|
|
||
| private static void customizeResources(OpenTelemetryConfigurationModel model) { | ||
| // this is equivalent to adding the following explicitly in declarative configuration | ||
| // | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| file_format: "1.0" | ||
| resource: | ||
| attributes: | ||
| # use this to set custom resource attributes | ||
| # - name: custom.attribute | ||
| # value: custom.attribute.value | ||
|
|
||
| # get attributes from OTEL_RESOURCE_ATTRIBUTES environment variable if set | ||
| attributes_list: ${OTEL_RESOURCE_ATTRIBUTES:-} | ||
|
|
||
| detection/development: | ||
| detectors: | ||
| # Enable cloud provider resource attributes detectors by default for easier onboarding. | ||
| # Those may slow down application startup, thus only the relevant ones should be enabled in production | ||
| - aws: | ||
| - azure: | ||
| - gcp: | ||
| # Provides 'process.*' attributes, including 'process.pid' | ||
| - process: | ||
| # Provides 'host.id' | ||
| - host: | ||
| # Provides 'container.id' | ||
| - container: | ||
| # Provides 'service.name' and 'service.instance.id' | ||
| - service: | ||
|
|
||
| tracer_provider: | ||
| processors: | ||
| - batch: | ||
| exporter: | ||
| otlp_http: | ||
| # get endpoint from OTEL_EXPORTER_OTLP_ENDPOINT environment variable if set, otherwise fallback to local collector | ||
| endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/traces | ||
| # get endpoint headers (like authentication) from OTEL_EXPORTER_OTLP_HEADERS environment variable if set | ||
| headers_list: ${OTEL_EXPORTER_OTLP_HEADERS} | ||
|
|
||
| meter_provider: | ||
| readers: | ||
| - periodic: | ||
| exporter: | ||
| otlp_http: | ||
| # get endpoint from OTEL_EXPORTER_OTLP_ENDPOINT environment variable if set, otherwise fallback to local collector | ||
| endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/metrics | ||
| # get endpoint headers (like authentication) from OTEL_EXPORTER_OTLP_HEADERS environment variable if set | ||
| headers_list: ${OTEL_EXPORTER_OTLP_HEADERS} | ||
|
|
||
| logger_provider: | ||
| processors: | ||
| - batch: | ||
| exporter: | ||
| otlp_http: | ||
| # get endpoint from OTEL_EXPORTER_OTLP_ENDPOINT environment variable if set, otherwise fallback to local collector | ||
| endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/logs | ||
| # get endpoint headers (like authentication) from OTEL_EXPORTER_OTLP_HEADERS environment variable if set | ||
| headers_list: ${OTEL_EXPORTER_OTLP_HEADERS} | ||
|
|
||
| instrumentation/development: | ||
| java: | ||
| runtime_telemetry: | ||
| # emit not-yet stable runtime telemetry metrics which are currently part of semconv for java runtime | ||
| emit_experimental_metrics/development: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| /* | ||
| * Licensed to Elasticsearch B.V. under one or more contributor | ||
| * license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright | ||
| * ownership. Elasticsearch B.V. licenses this file to you under | ||
| * the Apache License, Version 2.0 (the "License"); you may | ||
| * not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
| package co.elastic.otel.declarativeconfig; | ||
|
|
||
| import static co.elastic.otel.declarativeconfig.ElasticDeclarativeConfigurationCustomizerTest.*; | ||
| import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; | ||
| import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json; | ||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| import io.opentelemetry.javaagent.tooling.resources.ResourceCustomizerProvider; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; | ||
| import java.io.InputStream; | ||
| import java.util.function.Consumer; | ||
| import net.javacrumbs.jsonunit.assertj.JsonListAssert; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| public class DefaultDeclarativeConfigTest { | ||
|
|
||
| // For now, we can't override env variable for testing, thus we just verify the default values | ||
| // in the configuration we provide. | ||
| @Test | ||
| void testDefaults() { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] this tests that the yaml has a correct structure and contains the things we hope it contains, it does not really checks that everything in it is actually correct, which is what the smoke test provides. |
||
| test( | ||
| (config) -> { | ||
| assertThat(config.getResource()).isNotNull(); | ||
| assertThat(config.getResource().getAttributesList()).isNull(); | ||
|
|
||
| assertThatJson(json(config.getResource())).inPath("attributes").isArray().isEmpty(); | ||
| JsonListAssert detectorsAssert = | ||
| assertThatJson(json(config.getResource())) | ||
| .inPath("detection/development.detectors") | ||
| .isArray() | ||
| .hasSize(9); | ||
|
|
||
| // those are the providers magically added by upstream and elastic distributions | ||
| detectorsAssert | ||
| .first() | ||
| .isEqualTo(json("{\"opentelemetry_javaagent_distribution\":null}")); | ||
| detectorsAssert.last().isEqualTo(json("{\"elastic_distribution\":null}")); | ||
|
|
||
| // those are the ones that should be included in the default configuration | ||
| detectorsAssert.contains( | ||
| json("{\"aws\":null}"), | ||
| json("{\"gcp\":null}"), | ||
| json("{\"azure\":null}"), | ||
| // TODO: maybe investigate why those are including empty objects | ||
| json("{\"process\":{}}}"), | ||
| json("{\"container\":{}}}"), | ||
| json("{\"service\":{}}}"), | ||
| json("{\"host\":{}}}")); | ||
|
SylvainJuge marked this conversation as resolved.
Outdated
|
||
|
|
||
| assertThat(config.getTracerProvider()).isNotNull(); | ||
| assertThat(assertThat(config.getTracerProvider().getProcessors()).hasSize(1)); | ||
| assertThatJson(json((config.getTracerProvider().getProcessors().get(0)))) | ||
| .inPath("batch.exporter.otlp_http") | ||
| .isObject() | ||
| .containsEntry("endpoint", "http://localhost:4318/v1/traces"); | ||
|
|
||
| assertThat(config.getMeterProvider()).isNotNull(); | ||
| assertThat(assertThat(config.getMeterProvider().getReaders()).hasSize(1)); | ||
| assertThatJson(json((config.getMeterProvider().getReaders().get(0)))) | ||
| .inPath("periodic.exporter.otlp_http") | ||
| .isObject() | ||
| .containsEntry("endpoint", "http://localhost:4318/v1/metrics"); | ||
|
|
||
| assertThat(config.getLoggerProvider()).isNotNull(); | ||
| assertThat(assertThat(config.getLoggerProvider().getProcessors()).hasSize(1)); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| assertThatJson(json((config.getLoggerProvider().getProcessors().get(0)))) | ||
| .inPath("batch.exporter.otlp_http") | ||
| .isObject() | ||
| .containsEntry("endpoint", "http://localhost:4318/v1/logs"); | ||
|
SylvainJuge marked this conversation as resolved.
|
||
|
|
||
| assertThatJson(json(config.getInstrumentationDevelopment())) | ||
| .describedAs("experimental jvm runtime telemetry metrics enabled by default") | ||
| .inPath("java.runtime_telemetry.emit_experimental_metrics/development") | ||
| .isBoolean() | ||
| .isTrue(); | ||
| }); | ||
| } | ||
|
|
||
| private static void test(Consumer<OpenTelemetryConfigurationModel> configChecks) { | ||
|
|
||
| InputStream input = | ||
| DefaultDeclarativeConfigTest.class | ||
| .getClassLoader() | ||
| .getResourceAsStream("co/elastic/otel/config.yaml"); | ||
| assertThat(input).isNotNull(); | ||
| OpenTelemetryConfigurationModel config = DeclarativeConfiguration.parse(input); | ||
|
|
||
| // manually apply config customization for simplicity | ||
| config = applyConfigCustomize(config, new ElasticDeclarativeConfigurationCustomizer()); | ||
| config = applyConfigCustomize(config, new ResourceCustomizerProvider()); | ||
|
|
||
| configChecks.accept(config); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,9 +29,6 @@ | |
| import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalInstrumentationModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationPropertyModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; | ||
| import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel; | ||
|
|
@@ -83,12 +80,6 @@ void defaultConfig() { | |
| assertThat(model.getTracerProvider()).isNull(); | ||
| assertThat(model.getMeterProvider()).isNull(); | ||
| assertThat(model.getLoggerProvider()).isNull(); | ||
|
|
||
| // java experimental runtime metrics enabled by default | ||
| assertThatJson(json(model.getInstrumentationDevelopment())) | ||
| .inPath("java.runtime_telemetry.emit_experimental_metrics/development") | ||
| .isBoolean() | ||
| .isTrue(); | ||
| } | ||
|
|
||
| @ParameterizedTest | ||
|
|
@@ -245,28 +236,6 @@ void addUserAgentPriority() { | |
| .contains("user-agent", "custom-user-Agent"); | ||
| } | ||
|
|
||
| @Test | ||
| void optOutExperimentalRuntimeMetrics() { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] I'm happy to get rid of this "half hadooken code" |
||
| OpenTelemetryConfigurationModel model = | ||
| new OpenTelemetryConfigurationModel() | ||
| .withInstrumentationDevelopment( | ||
| new ExperimentalInstrumentationModel() | ||
| .withJava( | ||
| new ExperimentalLanguageSpecificInstrumentationModel() | ||
| .withAdditionalProperty( | ||
| "runtime_telemetry", | ||
| new ExperimentalLanguageSpecificInstrumentationPropertyModel() | ||
| .withAdditionalProperty( | ||
| "emit_experimental_metrics/development", false)))); | ||
|
|
||
| model = applyConfigCustomize(model, new ElasticDeclarativeConfigurationCustomizer()); | ||
|
|
||
| assertThatJson(json(model.getInstrumentationDevelopment())) | ||
| .inPath("java.runtime_telemetry.emit_experimental_metrics/development") | ||
| .isBoolean() | ||
| .isFalse(); | ||
| } | ||
|
|
||
| @NotNull | ||
| private static Map<String, String> userAgentHeader(String value) { | ||
| Map<String, String> header = new HashMap<>(); | ||
|
|
@@ -275,7 +244,7 @@ private static Map<String, String> userAgentHeader(String value) { | |
| return header; | ||
| } | ||
|
|
||
| private OpenTelemetryConfigurationModel applyConfigCustomize( | ||
| static OpenTelemetryConfigurationModel applyConfigCustomize( | ||
| OpenTelemetryConfigurationModel originalModel, | ||
| DeclarativeConfigurationCustomizerProvider customizerProvider) { | ||
| AtomicReference<OpenTelemetryConfigurationModel> resultModel = new AtomicReference<>(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.