├── o11y-backend ├── grafana-bootstrap.ini ├── prometheus.yaml ├── tempo-overrides.yaml ├── grafana-datasources.yaml └── tempo-config.yaml ├── .gitignore ├── images └── youtube.png ├── src └── main │ ├── resources │ ├── application.properties │ └── logback.xml │ └── java │ └── tutorial │ └── buildon │ └── aws │ └── o11y │ ├── HelloApp.java │ ├── Constants.java │ └── HelloAppController.java ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── collector-config-aws.yaml ├── collector-config-local.yaml ├── run-microservice.sh ├── LICENSE ├── docker-compose-aws.yaml ├── CONTRIBUTING.md ├── docker-compose.yaml ├── pom.xml └── README.md /o11y-backend/grafana-bootstrap.ini: -------------------------------------------------------------------------------- 1 | [feature_toggles] 2 | enable = tempoSearch tempoBackendSearch -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | tempo-data 3 | .vscode 4 | opentelemetry-javaagent-all.jar 5 | hello-app.log 6 | -------------------------------------------------------------------------------- /images/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/build-on-aws/instrumenting-java-apps-using-opentelemetry/HEAD/images/youtube.png -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.config.import=optional:dependencies.properties 2 | spring.application.name=hello-app 3 | server.port=8888 4 | -------------------------------------------------------------------------------- /o11y-backend/prometheus.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | scrape_configs: 6 | - job_name: 'collector' 7 | scrape_interval: 5s 8 | static_configs: 9 | - targets: [ 'collector:6666' ] 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /src/main/java/tutorial/buildon/aws/o11y/HelloApp.java: -------------------------------------------------------------------------------- 1 | package tutorial.buildon.aws.o11y; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class HelloApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(HelloApp.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.8.1-openjdk-17-slim 2 | 3 | VOLUME /tmp 4 | ADD . /usr/src/app 5 | WORKDIR /usr/src/app 6 | 7 | RUN mvn clean package -DskipTests 8 | RUN curl -L https://github.com/aws-observability/aws-otel-java-instrumentation/releases/download/v1.28.1/aws-opentelemetry-agent.jar --output opentelemetry-javaagent-all.jar 9 | ENTRYPOINT [ "java", "-javaagent:opentelemetry-javaagent-all.jar", "-jar", "target/hello-app-1.0.jar" ] 10 | -------------------------------------------------------------------------------- /o11y-backend/tempo-overrides.yaml: -------------------------------------------------------------------------------- 1 | overrides: 2 | "single-tenant": 3 | search_tags_allow_list: 4 | - "instance" 5 | ingestion_rate_strategy: "local" 6 | ingestion_rate_limit_bytes: 15000000 7 | ingestion_burst_size_bytes: 20000000 8 | max_traces_per_user: 10000 9 | max_global_traces_per_user: 0 10 | max_bytes_per_trace: 50000 11 | max_search_bytes_per_trace: 0 12 | max_bytes_per_tag_values_query: 5000000 13 | block_retention: 0s -------------------------------------------------------------------------------- /o11y-backend/grafana-datasources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | access: proxy 7 | orgId: 1 8 | url: http://prometheus:9090 9 | basicAuth: false 10 | isDefault: false 11 | version: 1 12 | editable: false 13 | - name: Tempo 14 | type: tempo 15 | access: proxy 16 | orgId: 1 17 | url: http://tempo:3200 18 | basicAuth: false 19 | isDefault: true 20 | version: 1 21 | editable: false 22 | apiVersion: 1 23 | uid: tempo 24 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/tutorial/buildon/aws/o11y/Constants.java: -------------------------------------------------------------------------------- 1 | package tutorial.buildon.aws.o11y; 2 | 3 | public interface Constants { 4 | 5 | public static final String METRIC_PREFIX = "custom.metric."; 6 | 7 | public static final String NUMBER_OF_EXEC_NAME = METRIC_PREFIX + "number.of.exec"; 8 | public static final String NUMBER_OF_EXEC_DESCRIPTION = "Count the number of executions."; 9 | 10 | public static final String HEAP_MEMORY_NAME = METRIC_PREFIX + "heap.memory"; 11 | public static final String HEAP_MEMORY_DESCRIPTION = "Reports heap memory utilization."; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /collector-config-aws.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | endpoint: 0.0.0.0:5555 6 | 7 | processors: 8 | batch: 9 | timeout: 5s 10 | send_batch_size: 1024 11 | 12 | exporters: 13 | awsemf: 14 | region: 'us-east-1' 15 | log_group_name: '/metrics/otel' 16 | log_stream_name: 'otel-using-java' 17 | awsxray: 18 | region: 'us-east-1' 19 | 20 | service: 21 | pipelines: 22 | metrics: 23 | receivers: [otlp] 24 | processors: [batch] 25 | exporters: [awsemf] 26 | traces: 27 | receivers: [otlp] 28 | processors: [batch] 29 | exporters: [awsxray] 30 | -------------------------------------------------------------------------------- /collector-config-local.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | endpoint: 0.0.0.0:5555 6 | 7 | processors: 8 | batch: 9 | timeout: 1s 10 | send_batch_size: 1024 11 | 12 | exporters: 13 | prometheus: 14 | endpoint: collector:6666 15 | namespace: default 16 | otlp: 17 | endpoint: tempo:4317 18 | tls: 19 | insecure: true 20 | 21 | service: 22 | pipelines: 23 | metrics: 24 | receivers: [otlp] 25 | processors: [batch] 26 | exporters: [prometheus] 27 | traces: 28 | receivers: [otlp] 29 | processors: [batch] 30 | exporters: [otlp] 31 | telemetry: 32 | logs: 33 | level: debug 34 | -------------------------------------------------------------------------------- /run-microservice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mvn clean package -Dmaven.test.skip=true 4 | 5 | AGENT_FILE=opentelemetry-javaagent-all.jar 6 | if [ ! -f "${AGENT_FILE}" ]; then 7 | curl -L https://github.com/aws-observability/aws-otel-java-instrumentation/releases/download/v1.28.1/aws-opentelemetry-agent.jar --output ${AGENT_FILE} 8 | fi 9 | 10 | export OTEL_TRACES_EXPORTER=otlp 11 | export OTEL_METRICS_EXPORTER=otlp 12 | export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:5555 13 | 14 | export OTEL_RESOURCE_ATTRIBUTES=service.name=hello-app,service.version=1.0 15 | export OTEL_TRACES_SAMPLER=always_on 16 | export OTEL_IMR_EXPORT_INTERVAL=1000 17 | export OTEL_METRIC_EXPORT_INTERVAL=1000 18 | 19 | java -javaagent:./${AGENT_FILE} -jar target/hello-app-1.0.jar 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /o11y-backend/tempo-config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 3200 3 | 4 | distributor: 5 | search_tags_deny_list: 6 | - "instance" 7 | - "version" 8 | receivers: 9 | jaeger: 10 | protocols: 11 | thrift_http: 12 | grpc: 13 | thrift_binary: 14 | thrift_compact: 15 | zipkin: 16 | otlp: 17 | protocols: 18 | http: 19 | grpc: 20 | opencensus: 21 | 22 | ingester: 23 | trace_idle_period: 10s 24 | max_block_bytes: 1_000_000 25 | max_block_duration: 5m 26 | 27 | compactor: 28 | compaction: 29 | compaction_window: 1h 30 | max_block_bytes: 100_000_000 31 | block_retention: 1h 32 | compacted_block_retention: 10m 33 | 34 | storage: 35 | trace: 36 | backend: local 37 | block: 38 | bloom_filter_false_positive: .05 39 | index_downsample_bytes: 1000 40 | encoding: zstd 41 | wal: 42 | path: /tmp/tempo/wal 43 | encoding: snappy 44 | local: 45 | path: /tmp/tempo/blocks 46 | pool: 47 | max_workers: 100 48 | queue_depth: 10000 49 | 50 | overrides: 51 | per_tenant_override_config: /etc/overrides.yaml -------------------------------------------------------------------------------- /docker-compose-aws.yaml: -------------------------------------------------------------------------------- 1 | version: '3.0' 2 | 3 | services: 4 | 5 | hello-app: 6 | build: . 7 | image: hello-app:latest 8 | container_name: hello-app 9 | hostname: hello-app 10 | depends_on: 11 | - collector 12 | ports: 13 | - "8888:8888" 14 | environment: 15 | - OTEL_TRACES_EXPORTER=otlp 16 | - OTEL_METRICS_EXPORTER=otlp 17 | - OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:5555 18 | - OTEL_TRACES_SAMPLER=always_on 19 | - OTEL_IMR_EXPORT_INTERVAL=5000 20 | - OTEL_METRIC_EXPORT_INTERVAL=5000 21 | - OTEL_RESOURCE_ATTRIBUTES=service.name=hello-app,service.version=1.0,deployment.environment=production 22 | healthcheck: 23 | interval: 5s 24 | retries: 10 25 | test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:8888/hello 26 | 27 | collector: 28 | image: public.ecr.aws/aws-observability/aws-otel-collector:latest 29 | container_name: collector 30 | hostname: collector 31 | command: ["--config=/etc/collector-config.yaml"] 32 | environment: 33 | - AWS_PROFILE=default 34 | volumes: 35 | - ./collector-config-aws.yaml:/etc/collector-config.yaml 36 | - ~/.aws:/root/.aws 37 | ports: 38 | - "5555:5555" 39 | 40 | networks: 41 | default: 42 | name: inst-java-apps-using-otel 43 | -------------------------------------------------------------------------------- /src/main/java/tutorial/buildon/aws/o11y/HelloAppController.java: -------------------------------------------------------------------------------- 1 | package tutorial.buildon.aws.o11y; 2 | 3 | import java.util.Objects; 4 | import javax.annotation.PostConstruct; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import io.opentelemetry.api.GlobalOpenTelemetry; 13 | import io.opentelemetry.api.metrics.LongCounter; 14 | import io.opentelemetry.api.metrics.Meter; 15 | import io.opentelemetry.api.trace.Span; 16 | import io.opentelemetry.api.trace.Tracer; 17 | import io.opentelemetry.context.Scope; 18 | import io.opentelemetry.instrumentation.annotations.WithSpan; 19 | 20 | import static tutorial.buildon.aws.o11y.Constants.*; 21 | import static java.lang.Runtime.*; 22 | 23 | @RestController 24 | public class HelloAppController { 25 | 26 | private static final Logger log = 27 | LoggerFactory.getLogger(HelloAppController.class); 28 | 29 | @Value("otel.traces.api.version") 30 | private String tracesApiVersion; 31 | 32 | @Value("otel.metrics.api.version") 33 | private String metricsApiVersion; 34 | 35 | private final Tracer tracer = 36 | GlobalOpenTelemetry.getTracer("io.opentelemetry.traces.hello", 37 | tracesApiVersion); 38 | 39 | private final Meter meter = 40 | GlobalOpenTelemetry.meterBuilder("io.opentelemetry.metrics.hello") 41 | .setInstrumentationVersion(metricsApiVersion) 42 | .build(); 43 | 44 | private LongCounter numberOfExecutions; 45 | 46 | @PostConstruct 47 | public void createMetrics() { 48 | 49 | numberOfExecutions = 50 | meter 51 | .counterBuilder(NUMBER_OF_EXEC_NAME) 52 | .setDescription(NUMBER_OF_EXEC_DESCRIPTION) 53 | .setUnit("int") 54 | .build(); 55 | 56 | meter 57 | .gaugeBuilder(HEAP_MEMORY_NAME) 58 | .setDescription(HEAP_MEMORY_DESCRIPTION) 59 | .setUnit("byte") 60 | .buildWithCallback( 61 | r -> { 62 | r.record(getRuntime().totalMemory() - getRuntime().freeMemory()); 63 | }); 64 | 65 | } 66 | 67 | @RequestMapping(method= RequestMethod.GET, value="/hello") 68 | public Response hello() { 69 | Response response = buildResponse(); 70 | // Creating a custom span 71 | Span span = tracer.spanBuilder("mySpan").startSpan(); 72 | try (Scope scope = span.makeCurrent()) { 73 | if (response.isValid()) { 74 | log.info("The response is valid."); 75 | } 76 | // Update the synchronous metric 77 | numberOfExecutions.add(1); 78 | } finally { 79 | span.end(); 80 | } 81 | return response; 82 | } 83 | 84 | @WithSpan 85 | private Response buildResponse() { 86 | return new Response("Hello World"); 87 | } 88 | 89 | private record Response (String message) { 90 | private Response { 91 | Objects.requireNonNull(message); 92 | } 93 | private boolean isValid() { 94 | return true; 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.0' 2 | 3 | services: 4 | 5 | hello-app: 6 | build: . 7 | image: hello-app:latest 8 | container_name: hello-app 9 | hostname: hello-app 10 | depends_on: 11 | - collector 12 | ports: 13 | - "8888:8888" 14 | environment: 15 | - OTEL_TRACES_EXPORTER=otlp 16 | - OTEL_METRICS_EXPORTER=otlp 17 | - OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:5555 18 | - OTEL_TRACES_SAMPLER=always_on 19 | - OTEL_IMR_EXPORT_INTERVAL=5000 20 | - OTEL_METRIC_EXPORT_INTERVAL=5000 21 | - OTEL_RESOURCE_ATTRIBUTES=service.name=hello-app,service.version=1.0,deployment.environment=development 22 | healthcheck: 23 | interval: 5s 24 | retries: 10 25 | test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:8888/hello 26 | 27 | collector: 28 | image: otel/opentelemetry-collector:latest 29 | container_name: collector 30 | hostname: collector 31 | depends_on: 32 | tempo: 33 | condition: service_healthy 34 | prometheus: 35 | condition: service_healthy 36 | command: ["--config=/etc/collector-config.yaml"] 37 | volumes: 38 | - ./collector-config-local.yaml:/etc/collector-config.yaml 39 | ports: 40 | - "5555:5555" 41 | - "6666:6666" 42 | 43 | tempo: 44 | image: grafana/tempo:1.5.0 45 | command: [ "-search.enabled=true", "-config.file=/etc/tempo.yaml" ] 46 | container_name: tempo 47 | hostname: tempo 48 | volumes: 49 | - ./o11y-backend/tempo-config.yaml:/etc/tempo.yaml 50 | - ./o11y-backend/tempo-overrides.yaml:/etc/overrides.yaml 51 | - ./tempo-data:/tmp/tempo 52 | ports: 53 | - "3200:3200" 54 | - "4317:4317" 55 | healthcheck: 56 | interval: 5s 57 | retries: 10 58 | test: wget --no-verbose --tries=1 --spider http://localhost:3200/status || exit 1 59 | 60 | prometheus: 61 | image: prom/prometheus:v2.39.2 62 | container_name: prometheus 63 | hostname: prometheus 64 | command: 65 | - --config.file=/etc/prometheus.yaml 66 | - --web.enable-remote-write-receiver 67 | - --enable-feature=exemplar-storage 68 | volumes: 69 | - ./o11y-backend/prometheus.yaml:/etc/prometheus.yaml 70 | ports: 71 | - "9090:9090" 72 | healthcheck: 73 | interval: 5s 74 | retries: 10 75 | test: wget --no-verbose --tries=1 --spider http://localhost:9090/status || exit 1 76 | 77 | grafana: 78 | image: grafana/grafana:9.2.2 79 | container_name: grafana 80 | hostname: grafana 81 | depends_on: 82 | tempo: 83 | condition: service_healthy 84 | prometheus: 85 | condition: service_healthy 86 | volumes: 87 | - ./o11y-backend/grafana-bootstrap.ini:/etc/grafana/grafana.ini 88 | - ./o11y-backend/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml 89 | environment: 90 | - GF_AUTH_ANONYMOUS_ENABLED=true 91 | - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin 92 | - GF_AUTH_DISABLE_LOGIN_FORM=true 93 | ports: 94 | - "3000:3000" 95 | healthcheck: 96 | interval: 5s 97 | retries: 10 98 | test: wget --no-verbose --tries=1 --spider http://localhost:3000 || exit 1 99 | 100 | networks: 101 | default: 102 | name: inst-java-apps-using-otel 103 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | tutorial.buildon.aws.o11y 7 | hello-app 8 | 1.0 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 3.1.2 14 | 15 | 16 | 17 | 18 | 17 19 | 0.13.1 20 | 1.10.0-alpha-rc.1 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-actuator 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-devtools 35 | runtime 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | junit 44 | junit 45 | 4.13.2 46 | compile 47 | 48 | 49 | javax.annotation 50 | javax.annotation-api 51 | 1.3.2 52 | 53 | 54 | io.opentelemetry 55 | opentelemetry-api 56 | 1.28.0 57 | 58 | 59 | io.opentelemetry.instrumentation 60 | opentelemetry-instrumentation-annotations 61 | 1.28.0 62 | 63 | 64 | io.opentelemetry 65 | opentelemetry-api-trace 66 | ${otel.traces.api.version} 67 | 68 | 69 | io.opentelemetry 70 | opentelemetry-api-metrics 71 | ${otel.metrics.api.version} 72 | 73 | 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-compiler-plugin 79 | 3.11.0 80 | 81 | 17 82 | 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-maven-plugin 87 | 88 | 89 | org.codehaus.mojo 90 | properties-maven-plugin 91 | 1.2.0 92 | 93 | 94 | package 95 | 96 | write-project-properties 97 | 98 | 99 | ${project.build.outputDirectory}/dependencies.properties 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Instrumenting Java Applications using OpenTelemetry 2 | 3 | This project provides an example of microservice written in Java that produces telemetry data for traces and metrics using [OpenTelemetry](https://opentelemetry.io). It also shows how to de-couple the application from the observability backend using the [OpenTelemetry Collector](https://opentelemetry.io/docs/collector) and the [OTLP protocol](https://opentelemetry.io/docs/reference/specification/protocol), so you can be easily switch the observability backend for another without code changes. 4 | 5 | 💡 If you want to learn how to build this code with a hands-on tutorial, you can watch the YouTube series below. 6 | 7 | [![Instrumenting Java Applications using OpenTelemetry](images/youtube.png)](https://www.youtube.com/watch?v=XvmicNH_4lc&list=PLDqi6CuDzubz5viRapQ049TjJMOCCu9MJ&index=1) 8 | 9 | Alternatively, you can also read the blog post: https://www.buildon.aws/posts/instrumenting-java-apps-using-opentelemetry 10 | 11 | ### Requirements 12 | 13 | * [Java 17+](https://openjdk.org/install) 14 | * [Maven 3.8.6+](https://maven.apache.org/download.cgi) 15 | * [Docker](https://www.docker.com/get-started) 16 | 17 | ## 🏢 Running the microservice with Grafana, Grafana Tempo, and Prometheus as observability backend. 18 | 19 | You can have the microservice sending telemetry data to a local observability backend. Traces will be sent to [Grafana Tempo](https://grafana.com/traces) and the metrics to [Prometheus](https://prometheus.io). Then you can use [Grafana](https://grafana.com/grafana) to visualize the the generated telemetry data. 20 | 21 | 1. Start the containers using Docker Compose. 22 | 23 | ```bash 24 | docker compose -f docker-compose.yaml up -d 25 | ``` 26 | 27 | 2. Access the Grafana UI: http://localhost:3000 28 | 29 | ## 🌩 Running the microservice with AWS X-Ray and Amazon CloudWatch as observability backend. 30 | 31 | You can have the microservice sending telemetry data to AWS as observability backend. Traces will be sent to [AWS X-Ray](https://aws.amazon.com/xray) and the metrics to [Amazon CloudWatch](https://aws.amazon.com/cloudwatch). This is possible thanks to the [AWS Distro for OpenTelemetry](https://aws.amazon.com/otel) that provides out-of-the-box integration with AWS services. Before running the code; make sure to [configure your AWS credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html) in your machine, as the code will use them to connect with the target services. 32 | 33 | 1. Start the containers using Docker Compose. 34 | 35 | ```bash 36 | docker compose -f docker-compose-aws.yaml up -d 37 | ``` 38 | 39 | 2. Access the AWS Console: https://console.aws.amazon.com 40 | 41 | ## ⚡️ Invoke the Microservice API manually 42 | 43 | The microservice expose an API over the port 8888 using HTTP. 44 | 45 | 1. Invoke this API for testing purposes. 46 | 47 | ```bash 48 | curl -X GET http://localhost:8888/hello 49 | ``` 50 | 51 | ## Security 52 | 53 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 54 | 55 | ## Disclaimers 56 | 57 | ```text 58 | This package requires and may incorporate or retrieve a number of third-party 59 | software packages (such as open source packages) at install-time or build-time 60 | or run-time ("External Dependencies"). The External Dependencies are subject to 61 | license terms that you must accept in order to use this package. If you do not 62 | accept all of the applicable license terms, you should not use this package. We 63 | recommend that you consult your company's open source approval policy before 64 | proceeding. 65 | 66 | Provided below is a list of External Dependencies and the applicable license 67 | identification as indicated by the documentation associated with the External 68 | Dependencies as of Amazon's most recent review. 69 | 70 | THIS INFORMATION IS PROVIDED FOR CONVENIENCE ONLY. AMAZON DOES NOT PROMISE THAT 71 | THE LIST OR THE APPLICABLE TERMS AND CONDITIONS ARE COMPLETE, ACCURATE, OR 72 | UP-TO-DATE, AND AMAZON WILL HAVE NO LIABILITY FOR ANY INACCURACIES. YOU SHOULD 73 | CONSULT THE DOWNLOAD SITES FOR THE EXTERNAL DEPENDENCIES FOR THE MOST COMPLETE 74 | AND UP-TO-DATE LICENSING INFORMATION. 75 | 76 | YOUR USE OF THE EXTERNAL DEPENDENCIES IS AT YOUR SOLE RISK. IN NO EVENT WILL 77 | AMAZON BE LIABLE FOR ANY DAMAGES, INCLUDING WITHOUT LIMITATION ANY DIRECT, 78 | INDIRECT, CONSEQUENTIAL, SPECIAL, INCIDENTAL, OR PUNITIVE DAMAGES (INCLUDING 79 | FOR ANY LOSS OF GOODWILL, BUSINESS INTERRUPTION, LOST PROFITS OR DATA, OR 80 | COMPUTER FAILURE OR MALFUNCTION) ARISING FROM OR RELATING TO THE EXTERNAL 81 | DEPENDENCIES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, EVEN 82 | IF AMAZON HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 83 | AND DISCLAIMERS APPLY EXCEPT TO THE EXTENT PROHIBITED BY APPLICABLE LAW. 84 | 85 | Grafana (https://grafana.com) – Affero General Public License 3.0 86 | ``` 87 | 88 | ## License 89 | 90 | This library is licensed under the MIT-0 License. See the [LICENSE](./LICENSE) file. 91 | --------------------------------------------------------------------------------