bootJar { manifest { attributes('Implementation-Title': 'Demo Application', 'Implementation-Version': version) } }The `service.instance.id` attribute will be set if any of the following return a value. The list is in order of precedence.
For example, you can add service.version
to make it easier to see if a new
18 | * version of the application is causing a problem.
19 | *
20 | *
The attributes service.name
, service.version
, and
21 | * service.instance.id
are automatically detected as outlined below.
22 | *
23 | *
For service.name
the order of precedence is:
24 | *
25 | *
The following block can be added to build.gradle to set the application name and version in 34 | * the jar's MANIFEST.MF: 35 | * 36 | *
37 | * bootJar { 38 | * manifest { 39 | * attributes('Implementation-Title': 'Demo Application', 40 | * 'Implementation-Version': version) 41 | * } 42 | * } 43 | *44 | * 45 | * The
service.instance.id
attribute will be set if any of the following return a
46 | * value. The list is in order of precedence.
47 | *
48 | * This will also send metrics and traces to Loki as an unintended side effect. 61 | */ 62 | private boolean debugLogging; 63 | 64 | /** 65 | * Enable or disable the OpenTelemetry integration (default is enabled). 66 | * 67 | *
This can be used to disable the integration without removing the dependency.
68 | */
69 | private boolean enabled = true;
70 |
71 | public CloudProperties getCloud() {
72 | return cloud;
73 | }
74 |
75 | public void setCloud(CloudProperties cloud) {
76 | this.cloud = cloud;
77 | }
78 |
79 | public OnPremProperties getOnPrem() {
80 | return onPrem;
81 | }
82 |
83 | public void setOnPrem(OnPremProperties onPrem) {
84 | this.onPrem = onPrem;
85 | }
86 |
87 | public boolean isDebugLogging() {
88 | return debugLogging;
89 | }
90 |
91 | public void setDebugLogging(boolean debugLogging) {
92 | this.debugLogging = debugLogging;
93 | }
94 |
95 | public boolean isEnabled() {
96 | return enabled;
97 | }
98 |
99 | public void setEnabled(boolean enabled) {
100 | this.enabled = enabled;
101 | }
102 |
103 | public Map Use Leave Leave You do not need to set an Use onprem.endpoint
instead of zone
when using the Grafana
112 | * Agent.
113 | */
114 | private String zone;
115 |
116 | /**
117 | * The Instance ID can be found when you click on "Details" in the "Grafana" section on
118 | * grafana.com.
119 | *
120 | * instanceId
empty when using the Grafana Agent.
121 | */
122 | private int instanceId;
123 |
124 | /**
125 | * Create an API key under "Security" / "API Keys" (left side navigation tree) on grafana.com.
126 | * The role should be "MetricsPublisher"
127 | *
128 | * apiKey
empty when using the Grafana Agent.
129 | */
130 | private String apiKey;
131 |
132 | public String getZone() {
133 | return zone;
134 | }
135 |
136 | public void setZone(String zone) {
137 | this.zone = zone;
138 | }
139 |
140 | public int getInstanceId() {
141 | return instanceId;
142 | }
143 |
144 | public void setInstanceId(int instanceId) {
145 | this.instanceId = instanceId;
146 | }
147 |
148 | public String getApiKey() {
149 | return apiKey;
150 | }
151 |
152 | public void setApiKey(String apiKey) {
153 | this.apiKey = apiKey;
154 | }
155 | }
156 |
157 | public static class OnPremProperties {
158 | /**
159 | * The endpoint of the Grafana Agent.
160 | *
161 | * endpoint
value if your Grafana Agent is running
162 | * locally with the default gRPC endpoint (localhost:4317).
163 | *
164 | * cloud.zone
instead of endpoint
when using the Grafana Cloud.
165 | */
166 | private String endpoint;
167 |
168 | /**
169 | * The protocol used to send OTLP data. Can be either http/protobuf
or grpc
170 | *
(default).
171 | */
172 | private String protocol;
173 |
174 | public String getEndpoint() {
175 | return endpoint;
176 | }
177 |
178 | public void setEndpoint(String endpoint) {
179 | this.endpoint = endpoint;
180 | }
181 |
182 | public String getProtocol() {
183 | return protocol;
184 | }
185 |
186 | public void setProtocol(String protocol) {
187 | this.protocol = protocol;
188 | }
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/main/java/com/grafana/opentelemetry/Log4jConfig.java:
--------------------------------------------------------------------------------
1 | package com.grafana.opentelemetry;
2 |
3 | import io.opentelemetry.api.OpenTelemetry;
4 | import io.opentelemetry.instrumentation.log4j.appender.v2_17.OpenTelemetryAppender;
5 | import org.apache.logging.log4j.LogManager;
6 | import org.apache.logging.log4j.Logger;
7 | import org.apache.logging.log4j.core.Appender;
8 | import org.apache.logging.log4j.core.LoggerContext;
9 | import org.apache.logging.log4j.core.config.Configuration;
10 | import org.apache.logging.log4j.core.config.LoggerConfig;
11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
12 |
13 | @ConditionalOnClass(name = "org.apache.logging.log4j.core.LoggerContext")
14 | public class Log4jConfig implements LogAppenderConfigurer {
15 |
16 | private static final Logger logger = LogManager.getLogger(Log4jConfig.class);
17 |
18 | public void tryAddAppender(OpenTelemetry openTelemetry) {
19 | org.apache.logging.log4j.spi.LoggerContext loggerContextSpi = LogManager.getContext(false);
20 | if (!(loggerContextSpi instanceof LoggerContext)) {
21 | logger.warn("cannot add log4j OpenTelemetryAppender, not running in a LoggerContext");
22 | return;
23 | }
24 |
25 | LoggerContext context = (LoggerContext) LogManager.getContext(false);
26 | Configuration config = context.getConfiguration();
27 | boolean found =
28 | config.getAppenders().values().stream()
29 | .anyMatch(
30 | a ->
31 | a
32 | instanceof
33 | io.opentelemetry.instrumentation.log4j.appender.v2_17
34 | .OpenTelemetryAppender);
35 | if (found) {
36 | logger.info("log4j2 OpenTelemetryAppender has already been added");
37 | OpenTelemetryAppender.install(openTelemetry);
38 | return;
39 | }
40 |
41 | logger.info("adding log4j OpenTelemetryAppender");
42 | OpenTelemetryAppender appender =
43 | OpenTelemetryAppender.builder()
44 | .setCaptureExperimentalAttributes(true)
45 | .setName("OpenTelemetryAppender")
46 | .setConfiguration(config)
47 | .setOpenTelemetry(openTelemetry)
48 | .build();
49 | appender.start();
50 | config.addAppender(appender);
51 |
52 | updateLoggers(appender, config);
53 | }
54 |
55 | private static void updateLoggers(Appender appender, Configuration config) {
56 | for (LoggerConfig loggerConfig : config.getLoggers().values()) {
57 | loggerConfig.addAppender(appender, null, null);
58 | }
59 | config.getRootLogger().addAppender(appender, null, null);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/grafana/opentelemetry/LogAppenderConfigurer.java:
--------------------------------------------------------------------------------
1 | package com.grafana.opentelemetry;
2 |
3 | import io.opentelemetry.api.OpenTelemetry;
4 |
5 | public interface LogAppenderConfigurer {
6 | void tryAddAppender(OpenTelemetry openTelemetry);
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/grafana/opentelemetry/LogbackConfig.java:
--------------------------------------------------------------------------------
1 | package com.grafana.opentelemetry;
2 |
3 | import io.opentelemetry.api.OpenTelemetry;
4 | import io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender;
5 | import java.util.concurrent.atomic.AtomicBoolean;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
9 |
10 | @ConditionalOnClass(name = "ch.qos.logback.classic.Logger")
11 | public class LogbackConfig implements LogAppenderConfigurer {
12 |
13 | private static final Logger logger = LoggerFactory.getLogger(LogbackConfig.class);
14 |
15 | public void tryAddAppender(OpenTelemetry openTelemetry) {
16 | ch.qos.logback.classic.Logger logbackLogger = getLogger();
17 |
18 | // check if appender has been added manually already
19 | if (hasAppender(logbackLogger)) {
20 | logger.info("logback OpenTelemetryAppender has already been added");
21 | OpenTelemetryAppender.install(openTelemetry);
22 | return;
23 | }
24 |
25 | logger.info("adding logback OpenTelemetryAppender");
26 | OpenTelemetryAppender appender = new OpenTelemetryAppender();
27 | appender.setCaptureExperimentalAttributes(true);
28 | appender.setOpenTelemetry(openTelemetry);
29 | appender.start();
30 | logbackLogger.addAppender(appender);
31 | }
32 |
33 | static ch.qos.logback.classic.Logger getLogger() {
34 | return (ch.qos.logback.classic.Logger)
35 | LoggerFactory.getILoggerFactory().getLogger(Logger.ROOT_LOGGER_NAME);
36 | }
37 |
38 | static boolean hasAppender(ch.qos.logback.classic.Logger logbackLogger) {
39 | AtomicBoolean found = new AtomicBoolean(false);
40 | logbackLogger
41 | .iteratorForAppenders()
42 | .forEachRemaining(
43 | appender -> {
44 | if (appender instanceof OpenTelemetryAppender) {
45 | found.set(true);
46 | }
47 | });
48 | return found.get();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/grafana/opentelemetry/OpenTelemetryConfig.java:
--------------------------------------------------------------------------------
1 | package com.grafana.opentelemetry;
2 |
3 | import io.micrometer.core.instrument.Clock;
4 | import io.micrometer.core.instrument.MeterRegistry;
5 | import io.opentelemetry.api.OpenTelemetry;
6 | import io.opentelemetry.api.common.AttributeKey;
7 | import io.opentelemetry.instrumentation.micrometer.v1_5.OpenTelemetryMeterRegistry;
8 | import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
9 | import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
10 | import io.opentelemetry.sdk.metrics.Aggregation;
11 | import io.opentelemetry.sdk.metrics.InstrumentSelector;
12 | import io.opentelemetry.sdk.metrics.InstrumentType;
13 | import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
14 | import io.opentelemetry.sdk.metrics.View;
15 | import io.opentelemetry.sdk.metrics.internal.aggregator.ExplicitBucketHistogramUtils;
16 | import io.opentelemetry.semconv.ResourceAttributes;
17 | import java.net.InetAddress;
18 | import java.net.UnknownHostException;
19 | import java.util.Base64;
20 | import java.util.HashMap;
21 | import java.util.List;
22 | import java.util.Map;
23 | import java.util.Optional;
24 | import java.util.concurrent.TimeUnit;
25 | import java.util.jar.Attributes;
26 | import java.util.jar.Manifest;
27 | import java.util.stream.Collectors;
28 | import org.apache.logging.log4j.util.Strings;
29 | import org.slf4j.Logger;
30 | import org.slf4j.LoggerFactory;
31 | import org.springframework.beans.factory.annotation.Value;
32 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
33 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
34 | import org.springframework.context.annotation.Bean;
35 | import org.springframework.context.annotation.Configuration;
36 | import org.springframework.context.annotation.PropertySource;
37 |
38 | @Configuration(proxyBeanMethods = false)
39 | @ConditionalOnProperty(value = "grafana.otlp.enabled", havingValue = "true", matchIfMissing = true)
40 | @EnableConfigurationProperties(GrafanaProperties.class)
41 | @PropertySource(value = {"classpath:grafana-otel-starter.properties"})
42 | public class OpenTelemetryConfig {
43 |
44 | public static final String DISTRIBUTION_NAME = "telemetry.distro.name";
45 | public static final String DISTRIBUTION_VERSION = "telemetry.distro.version";
46 |
47 | private static final Logger logger = LoggerFactory.getLogger(OpenTelemetryConfig.class);
48 |
49 | public static final String OTLP_HEADERS = "otel.exporter.otlp.headers";
50 |
51 | @Bean
52 | public MeterRegistry openTelemetryMeterRegistry(OpenTelemetry openTelemetry, Clock clock) {
53 | // note: add setting histogramGaugesEnabled in new otel version
54 | return OpenTelemetryMeterRegistry.builder(openTelemetry)
55 | .setClock(clock)
56 | .setBaseTimeUnit(TimeUnit.SECONDS)
57 | .build();
58 | }
59 |
60 | @Bean
61 | public OpenTelemetry openTelemetry(
62 | Optional