diff --git a/pom.xml b/pom.xml index 6ea3dd6e6..a1f7e80aa 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,44 @@ + + + + + io.opentelemetry + opentelemetry-bom + 1.12.0 + pom + import + + + + + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-sdk + + + io.opentelemetry + opentelemetry-exporter-otlp-http-trace + + + io.opentelemetry + opentelemetry-semconv + 1.12.0-alpha + + + org.springframework.boot diff --git a/run.sh b/run.sh new file mode 100644 index 000000000..d62321bc5 --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + + +OTEL_RESOURCE_ATTRIBUTES="service.name=spring-petclinic,service.version=1.0.0" + + +java -jar target/spring-petclinic-3.0.0-SNAPSHOT.jar \ No newline at end of file diff --git a/src/main/java/org/springframework/samples/petclinic/OpenTelemetryInstrumentation.java b/src/main/java/org/springframework/samples/petclinic/OpenTelemetryInstrumentation.java new file mode 100644 index 000000000..c38e60fa1 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/OpenTelemetryInstrumentation.java @@ -0,0 +1,31 @@ + +package org.springframework.samples.petclinic; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; + + +public class OpenTelemetryInstrumentation { + + public static void instrumentTracing() { + Tracer tracer = GlobalOpenTelemetry + .getTracerProvider() + .tracerBuilder("my-tracer") //TODO Replace with the name of your tracer + .build(); + + Span span = tracer + .spanBuilder("my-span") //TODO Replace with the name of your span + .setAttribute("my-key-1", "my-value-1") //TODO Add initial attributes + .startSpan(); + + try (Scope scope = span.makeCurrent()) { + span.setAttribute("key-2", "value-2"); //TODO Add extra attributes if necessary + //TODO your code goes here + } finally { + span.end(); + + } + + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/OtelExporter.java b/src/main/java/org/springframework/samples/petclinic/OtelExporter.java new file mode 100644 index 000000000..d02c64c98 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/OtelExporter.java @@ -0,0 +1,70 @@ +package org.springframework.samples.petclinic; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.opentelemetry.sdk.trace.samplers.Sampler; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.Properties; +import java.util.stream.Stream; + + + +public class OtelExporter { + public static void initOpenTelemetry() throws IOException { + Resource serviceName = Optional.ofNullable(System.getenv("petClinic")) + .map(n -> Attributes.of(AttributeKey.stringKey("springPetClinic"), n)) + .map(Resource::create) + .orElseGet(Resource::empty); + + Resource envResourceAttributes = Resource.create(Stream.of(Optional.ofNullable(System.getenv("OTEL_RESOURCE_ATTRIBUTES")).orElse("").split(",")) + .filter(pair -> pair != null && pair.length() > 0 && pair.contains("=")) + .map(pair -> pair.split("=")) + .filter(pair -> pair.length == 2) + .collect(Attributes::builder, (b, p) -> b.put(p[0], p[1]), (b1, b2) -> b1.putAll(b2.build())) + .build() + ); + + + Resource dtMetadata = Resource.empty(); + for (String name : new String[] {"dt_metadata_e617c525669e072eebe3d0f08212e8f2.properties", "/var/lib/dynatrace/enrichment/dt_metadata.properties"}) { + try { + Properties props = new Properties(); + props.load(name.startsWith("/var") ? new FileInputStream(name) : new FileInputStream(Files.readAllLines(Paths.get(name)).get(0))); + dtMetadata = dtMetadata.merge(Resource.create(props.entrySet().stream() + .collect(Attributes::builder, (b, e) -> b.put(e.getKey().toString(), e.getValue().toString()), (b1, b2) -> b1.putAll(b2.build())) + .build()) + ); + } catch (IOException e) {} + } + + + SpanExporter exporter = OtlpHttpSpanExporter.builder() + .setEndpoint("http://englab-tdbank.datadog.hq.com") //TODO Replace to your SaaS/Managed-URL as mentioned in the next step + .addHeader("Authorization", "93ffd05f8f2a91e0b8a22e476e1bb3c6a3de5dcd") //TODO Replace with your API Token as mentioned in the next step + .build(); + + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .setResource(Resource.getDefault().merge(envResourceAttributes).merge(serviceName).merge(dtMetadata)) + .setSampler(Sampler.alwaysOn()) + .addSpanProcessor(BatchSpanProcessor.builder(exporter).build()) + .build(); + + OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .buildAndRegisterGlobal(); + Runtime.getRuntime().addShutdownHook(new Thread(sdkTracerProvider::close)); + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java b/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java index ac6e15030..88b12e7b7 100644 --- a/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java +++ b/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java @@ -14,24 +14,31 @@ * limitations under the License. */ -package org.springframework.samples.petclinic; + package org.springframework.samples.petclinic; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ImportRuntimeHints; + import org.aspectj.apache.bcel.classfile.Module; + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.context.annotation.ImportRuntimeHints; + + import java.io.IOException; /** - * PetClinic Spring Boot Application. - * - * @author Dave Syer - * - */ -@SpringBootApplication -@ImportRuntimeHints(PetClinicRuntimeHints.class) -public class PetClinicApplication { + * PetClinic Spring Boot Application. + * + * @author Dave Syer + * + */ + @SpringBootApplication + @ImportRuntimeHints(PetClinicRuntimeHints.class) + public class PetClinicApplication { - public static void main(String[] args) { - SpringApplication.run(PetClinicApplication.class, args); - } + public static void main(String[] args) throws IOException { + OtelExporter.initOpenTelemetry(); + OpenTelemetryInstrumentation.instrumentTracing(); + SpringApplication.run(PetClinicApplication.class, args); -} + + } + + }