Skip to content

Commit 0ff28bf

Browse files
committed
customize properties
1 parent 44592ae commit 0ff28bf

6 files changed

Lines changed: 224 additions & 66 deletions

File tree

custom/build.gradle

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,47 @@
11
plugins {
2-
id "java"
3-
id "org.owasp.dependencycheck" version "12.1.3"
2+
id "java"
3+
id "org.owasp.dependencycheck" version "12.1.3"
44
}
55

66
apply from: "$rootDir/gradle/checkstyle.gradle"
77

88
dependencies {
9-
compileOnly("io.opentelemetry:opentelemetry-sdk")
10-
compileOnly("io.opentelemetry.semconv:opentelemetry-semconv")
11-
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
12-
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator")
13-
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api")
14-
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling")
15-
16-
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv")
17-
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
18-
testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common")
19-
testImplementation("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api")
9+
compileOnly("io.opentelemetry:opentelemetry-sdk")
10+
compileOnly("io.opentelemetry.semconv:opentelemetry-semconv")
11+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
12+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator")
13+
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api")
14+
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling")
15+
16+
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv")
17+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
18+
testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common")
19+
testImplementation("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api")
20+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator")
2021
}
2122

2223
dependencyCheck {
23-
skipConfigurations = ["checkstyle", "annotationProcessor"]
24-
suppressionFile = "buildscripts/dependency-check-suppressions.xml"
25-
failBuildOnCVSS = 7.0f // fail on high or critical CVE
24+
skipConfigurations = ["checkstyle", "annotationProcessor"]
25+
suppressionFile = "buildscripts/dependency-check-suppressions.xml"
26+
failBuildOnCVSS = 7.0f // fail on high or critical CVE
2627
}
2728

2829
def updateGeneratedFile(file, newContent) {
29-
if (System.getenv("CHECK_GENERATED_FILES") == "true") {
30-
def oldContent = file.text
31-
if (oldContent != newContent) {
32-
throw new GradleException("File ${file} was modified in CI. Please update it locally and commit.")
30+
if (System.getenv("CHECK_GENERATED_FILES") == "true") {
31+
def oldContent = file.text
32+
if (oldContent != newContent) {
33+
throw new GradleException("File ${file} was modified in CI. Please update it locally and commit.")
34+
}
35+
} else {
36+
project.mkdir(file.parent)
37+
file.text = newContent
3338
}
34-
} else {
35-
project.mkdir(file.parent)
36-
file.text = newContent
37-
}
3839
}
3940

4041
tasks.register('manageVersionClass') {
41-
doLast {
42-
updateGeneratedFile(new File("${projectDir}/src/main/java/com/grafana/extensions/resources/internal", "DistributionVersion.java"),
43-
"""/*
42+
doLast {
43+
updateGeneratedFile(new File("${projectDir}/src/main/java/com/grafana/extensions/resources/internal", "DistributionVersion.java"),
44+
"""/*
4445
* Copyright Grafana Labs
4546
* SPDX-License-Identifier: Apache-2.0
4647
*/
@@ -54,7 +55,7 @@ public class DistributionVersion {
5455
public static final String VERSION = "$version";
5556
}
5657
""")
57-
}
58+
}
5859
}
5960

6061
compileJava.dependsOn(manageVersionClass)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright Grafana Labs
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package com.grafana.extensions;
7+
8+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationModel;
9+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel;
10+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
11+
import java.util.Map;
12+
13+
public class DeclarativeConfigPropertyCustomizer {
14+
public static void addProperties(
15+
OpenTelemetryConfigurationModel model, Map<String, String> properties) {
16+
ExperimentalLanguageSpecificInstrumentationModel java = getJava(model);
17+
18+
properties.forEach(
19+
(key, value) -> {
20+
if (!key.startsWith("otel.instrumentation.")) {
21+
throw new IllegalArgumentException("Invalid key: " + key);
22+
}
23+
String[] path =
24+
key.substring("otel.instrumentation.".length()).replace('-', '_').split("\\.");
25+
addProperty(java, path, value);
26+
});
27+
}
28+
29+
private static ExperimentalLanguageSpecificInstrumentationModel getJava(
30+
OpenTelemetryConfigurationModel model) {
31+
InstrumentationModel instrumentationDevelopment = model.getInstrumentationDevelopment();
32+
if (instrumentationDevelopment == null) {
33+
instrumentationDevelopment = new InstrumentationModel();
34+
model.withInstrumentationDevelopment(instrumentationDevelopment);
35+
}
36+
ExperimentalLanguageSpecificInstrumentationModel java = instrumentationDevelopment.getJava();
37+
if (java == null) {
38+
java = new ExperimentalLanguageSpecificInstrumentationModel();
39+
instrumentationDevelopment.withJava(java);
40+
}
41+
return java;
42+
}
43+
44+
@SuppressWarnings("unchecked")
45+
private static void addProperty(
46+
ExperimentalLanguageSpecificInstrumentationModel java, String[] path, String value) {
47+
// iterate through the suffix and create nested maps as needed
48+
Map<String, Object> current = java.getAdditionalProperties();
49+
50+
for (int i = 0; i < path.length; i++) {
51+
String segment = path[i];
52+
if (segment.isEmpty()) {
53+
throw new IllegalArgumentException("Invalid key segment: empty segment at position " + i);
54+
}
55+
56+
if (i == path.length - 1) {
57+
// last segment, set the value
58+
current.put(segment, value);
59+
} else {
60+
// intermediate segment, ensure it's a map
61+
Object next = current.get(segment);
62+
if (next == null) {
63+
// create a new map if it doesn't exist
64+
next = new java.util.HashMap<String, Object>();
65+
current.put(segment, next);
66+
} else if (!(next instanceof Map)) {
67+
throw new IllegalArgumentException("Invalid key segment: " + segment + " is not a map");
68+
}
69+
current = (Map<String, Object>) next;
70+
}
71+
}
72+
}
73+
}

custom/src/main/java/com/grafana/extensions/GrafanaAutoConfigCustomizerProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
2424
.addResourceCustomizer(ResourceCustomizer::truncate);
2525
}
2626

27-
private static Map<String, String> getDefaultProperties() {
27+
static Map<String, String> getDefaultProperties() {
2828
HashMap<String, String> map = new HashMap<>();
2929
map.put("otel.instrumentation.micrometer.base-time-unit", "s");
3030
map.put("otel.instrumentation.log4j-appender.experimental-log-attributes", "true");

custom/src/main/java/com/grafana/extensions/GrafanaDeclarativeConfigurationCustomizerProvider.java

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,24 @@
11
/*
2-
* Copyright The OpenTelemetry Authors
2+
* Copyright Grafana Labs
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

66
package com.grafana.extensions;
77

8+
import com.grafana.extensions.resources.internal.DistroComponentProvider;
89
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer;
910
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider;
10-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel;
11-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel;
12-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel;
13-
14-
import java.util.Collections;
15-
import java.util.List;
16-
import java.util.Objects;
17-
import java.util.Set;
18-
import java.util.stream.Collectors;
1911

2012
public class GrafanaDeclarativeConfigurationCustomizerProvider
2113
implements DeclarativeConfigurationCustomizerProvider {
22-
private static final List<String> REQUIRED_DETECTORS =
23-
Collections.singletonList("grafana-javaagent-distribution");
2414

2515
@Override
2616
public void customize(DeclarativeConfigurationCustomizer customizer) {
2717
customizer.addModelCustomizer(
2818
model -> {
29-
ResourceModel resource = model.getResource();
30-
if (resource == null) {
31-
resource = new ResourceModel();
32-
model.withResource(resource);
33-
}
34-
ExperimentalResourceDetectionModel detectionModel = resource.getDetectionDevelopment();
35-
if (detectionModel == null) {
36-
detectionModel = new ExperimentalResourceDetectionModel();
37-
resource.withDetectionDevelopment(detectionModel);
38-
}
39-
List<ExperimentalResourceDetectorModel> detectors =
40-
Objects.requireNonNull(detectionModel.getDetectors());
41-
Set<String> names =
42-
detectors.stream()
43-
.flatMap(detector -> detector.getAdditionalProperties().keySet().stream())
44-
.collect(Collectors.toSet());
45-
46-
for (String name : REQUIRED_DETECTORS) {
47-
if (!names.contains(name)) {
48-
ExperimentalResourceDetectorModel detector = new ExperimentalResourceDetectorModel();
49-
detector.getAdditionalProperties().put(name, null);
50-
detectors.add(detector);
51-
}
52-
}
19+
DistroComponentProvider.addDistroResourceProvider(model);
20+
DeclarativeConfigPropertyCustomizer.addProperties(
21+
model, GrafanaAutoConfigCustomizerProvider.getDefaultProperties());
5322
return model;
5423
});
5524
}

custom/src/main/java/com/grafana/extensions/resources/internal/DistroComponentProvider.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,66 @@
1+
/*
2+
* Copyright Grafana Labs
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
16
package com.grafana.extensions.resources.internal;
27

38
import com.grafana.extensions.resources.DistributionResource;
49
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
510
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
11+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel;
12+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel;
13+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
14+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel;
615
import io.opentelemetry.sdk.resources.Resource;
16+
import java.util.Collections;
17+
import java.util.List;
18+
import java.util.Objects;
19+
import java.util.Set;
20+
import java.util.stream.Collectors;
721

822
@SuppressWarnings("rawtypes")
923
public class DistroComponentProvider implements ComponentProvider<Resource> {
1024

25+
static final String GRAFANA_JAVAAGENT_DISTRIBUTION = "grafana-javaagent-distribution";
26+
private static final List<String> REQUIRED_DETECTORS =
27+
Collections.singletonList(GRAFANA_JAVAAGENT_DISTRIBUTION);
28+
29+
public static void addDistroResourceProvider(OpenTelemetryConfigurationModel model) {
30+
ResourceModel resource = model.getResource();
31+
if (resource == null) {
32+
resource = new ResourceModel();
33+
model.withResource(resource);
34+
}
35+
ExperimentalResourceDetectionModel detectionModel = resource.getDetectionDevelopment();
36+
if (detectionModel == null) {
37+
detectionModel = new ExperimentalResourceDetectionModel();
38+
resource.withDetectionDevelopment(detectionModel);
39+
}
40+
List<ExperimentalResourceDetectorModel> detectors =
41+
Objects.requireNonNull(detectionModel.getDetectors());
42+
Set<String> names =
43+
detectors.stream()
44+
.flatMap(detector -> detector.getAdditionalProperties().keySet().stream())
45+
.collect(Collectors.toSet());
46+
47+
for (String name : REQUIRED_DETECTORS) {
48+
if (!names.contains(name)) {
49+
ExperimentalResourceDetectorModel detector = new ExperimentalResourceDetectorModel();
50+
detector.getAdditionalProperties().put(name, null);
51+
detectors.add(detector);
52+
}
53+
}
54+
}
55+
1156
@Override
1257
public Class<Resource> getType() {
1358
return Resource.class;
1459
}
1560

1661
@Override
1762
public String getName() {
18-
return "grafana-javaagent-distribution";
63+
return GRAFANA_JAVAAGENT_DISTRIBUTION;
1964
}
2065

2166
@Override
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright Grafana Labs
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package com.grafana.extensions;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatCode;
10+
11+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
12+
import java.util.HashMap;
13+
import java.util.Map;
14+
import org.junit.jupiter.api.Test;
15+
16+
@SuppressWarnings("DataFlowIssue")
17+
class DeclarativeConfigPropertyCustomizerTest {
18+
@Test
19+
void testAddSimpleProperty() {
20+
OpenTelemetryConfigurationModel model = new OpenTelemetryConfigurationModel();
21+
DeclarativeConfigPropertyCustomizer.addProperties(
22+
model, Map.of("otel.instrumentation.foo", "baz"));
23+
assertThat(model.getInstrumentationDevelopment().getJava().getAdditionalProperties())
24+
.extracting("foo")
25+
.isEqualTo("baz");
26+
}
27+
28+
@Test
29+
void testAddNestedProperty() {
30+
OpenTelemetryConfigurationModel model = new OpenTelemetryConfigurationModel();
31+
DeclarativeConfigPropertyCustomizer.addProperties(
32+
model, Map.of("otel.instrumentation.foo.bar", "baz"));
33+
assertThat(model.getInstrumentationDevelopment().getJava().getAdditionalProperties())
34+
.extracting("foo")
35+
.extracting("bar")
36+
.isEqualTo("baz");
37+
}
38+
39+
@Test
40+
void testInvalidKeyThrows() {
41+
OpenTelemetryConfigurationModel model = new OpenTelemetryConfigurationModel();
42+
Map<String, String> properties = new HashMap<>();
43+
properties.put("invalid.key", "value");
44+
assertThatCode(() -> DeclarativeConfigPropertyCustomizer.addProperties(model, properties))
45+
.isInstanceOf(IllegalArgumentException.class);
46+
}
47+
48+
@Test
49+
void testEmptySegmentThrows() {
50+
OpenTelemetryConfigurationModel model = new OpenTelemetryConfigurationModel();
51+
Map<String, String> properties = new HashMap<>();
52+
properties.put("otel.instrumentation..foo", "value");
53+
assertThatCode(() -> DeclarativeConfigPropertyCustomizer.addProperties(model, properties))
54+
.isInstanceOf(IllegalArgumentException.class);
55+
}
56+
57+
@Test
58+
void testNonMapIntermediateThrows() {
59+
OpenTelemetryConfigurationModel model = new OpenTelemetryConfigurationModel();
60+
// First, set foo to a value
61+
DeclarativeConfigPropertyCustomizer.addProperties(
62+
model, Map.of("otel.instrumentation.foo", "value1"));
63+
// Now, try to set foo.bar, which should fail
64+
assertThatCode(
65+
() ->
66+
DeclarativeConfigPropertyCustomizer.addProperties(
67+
model, Map.of("otel.instrumentation.foo.bar", "value2")))
68+
.isInstanceOf(IllegalArgumentException.class);
69+
}
70+
}

0 commit comments

Comments
 (0)