A Hands-On Guide to OpenTelemetry: Using Automatic Instrumentation
This article continues onwards with learning the first steps in generating telemetry data using automatic instrumentation.
Join the DZone community and get the full member experience.
Join For FreeAre you ready to start your journey on the road to collecting telemetry data from your applications? Great observability begins with great instrumentation!
In this series, you'll explore how to adopt OpenTelemetry (OTel) and how to instrument an application to collect tracing telemetry. You'll learn how to leverage out-of-the-box automatic instrumentation tools and understand when it's necessary to explore more advanced manual instrumentation for your applications. By the end of this series, you'll have an understanding of how telemetry travels from your applications to the OpenTelemetry Collector, and be ready to bring OpenTelemetry to your future projects. Everything discussed here is supported by a hands-on, self-paced workshop authored by Paige Cruze.
The previous article introduced observability concepts and terms related to OpenTelemetry and its components. In this article, we continue onwards with our first steps in generating telemetry data using automatic instrumentation.
Taking our first steps with OpenTelemetry involves installing it on our machine, configuring the provided software development kit (SDK), building a demo application, running that application with automatic instrumentation, and verifying the trace data generated in our console output.
Getting Started
There are many languages available for developing our applications, and for many, OpenTelemetry provides auto-instrumentation without having to change existing application code. This auto-instrumentation is done using the provided API and SDK for the application language, which detects any needed libraries and exporter dependencies. In our demo application, we are focusing on Python Flask. Python dynamically injects byte code to capture telemetry from popular libraries and frameworks.
To get started, our first step will be setting up our demo application and testing auto-instrumentation on the Python application. Create a working project directory as follows:
- Download and unzip the following application project into your workshop directory from this location.
- Next, we build the provided container image, presented here using Podman (feel free to substitute with Docker if desired), using the project's
Buildfile
:
$ cd intro-to-instrument-v1.1
$ podman build -t hello-otel:base -f Buildfile
Successfully tagged localhost/hello-otel:base \ 516c5299a32b68e7a4634ce15d1fd659eed2164ebe945ef1673f7a55630e22c8
This container image contains our Python application, which will expose a web page on port 8000 in the container itself, which we will map here to our local port 8001 (feel free to use any port that you have available). Run the container image with the following command:
$ podman run -i -p 8001:8000 -e FLASK_RUN_PORT=8000 hello-otel:base
* Debug mode: off WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:8000 * Running on http://10.88.0.18:8000 Press CTRL+C to quit
Open http://localhost:8001 in a browser and you'll see the output that this page has been viewed one time, verifying that the application is running. Expect to see a log entry in our console every time we refresh the page.
10.88.0.18 - - [11/Jul/2024 10:24:55] "GET / HTTP/1.1" 200 -
There are three routes in this application that provide the functionality we can use to test OpenTelemetry tracing:
- http://localhost:8001/ - Displays a count of page loading
- http://localhost:8001/doggo- Displays random photo of a dog
- http://localhost:8001/rolldice - Displays number from 1 to 6
Next, we'll start by leveraging OTel auto-instrumentation for Python to see what we get for free telemetry data out of our application. First, stop the running container using CTRL-C.
Automatically Instrumenting Application
To start auto-instrumenting our application we will change the container image we build to include the following installation actions:
opentelemetry-distro[otlp]
- Installing the API, SDK,opentelemetry-bootstrap
, andopentelemetry-instrument
opentelemetry-bootstrap
- Installing instrumentation libraries corresponding to installed packages
Our build file can be found at automatic/Buildfile-auto and contains the following, with highlighting lines installing our instrumentation dependencies:
FROM python:3.12-bullseye WORKDIR /app COPY requirements.txt requirements.txt RUN pip install -r requirements.txt RUN pip install opentelemetry-distro[otelp]
RUNopentelemetry-bootstrap -a install COPY . . CMD [ "flask", "run", "--host=0.0.0.0"]
Build this container image with the following command:
$ podman build -t hello-otel:auto -f automatic/Buildfile-auto
Successfully tagged localhost/hello-otel:auto \ 516c5299a32b68e7a4634ce15d1fd659eed2164ebe945ef1673f7a55630e22c8
When we run this container image, we are going to wrap it with the OpenTelemetry agent, known as opentelemetry-instrument
, that dynamically injects byte code to capture telemetry. Configure a global tracer, which we set with a flag to output to the console, and provide a service name for our application with the following command:
$ podman run -i -p 8001:8000 -e FLASK_RUN_PORT=8000 hello-otel:auto \
opentelemetry-instrument \
--traces_exporter console \
--service_name hello-otel \
* Debug mode: off WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:8000 * Running on http://10.88.0.19:8000 Press CTRL+C to quit
Now generate telemetry data (tracing) in your console by opening the main page at http://localhost:8001 and note that it's just a single trace for GET/path. This is also the case for http://localhost:8001/rolldice, so let's take a look at the Doggo application path, which has a trace and several spans by loading http://localhost:8001/doggo.
Below we've presented one of the spans captured in the trace, the compile phase of the Jinja2 HTML template used to display the dog pictures:
{ "name": "jinja2.compile", "context": { "trace_id": "0x1b08c2d2b8fd2e237fcc7b34d83daa44", "span_id": "0xa80f805993195e50", "trace_state": "[]" }, "kind": "SpanKind.INTERNAL", "parent_id": "0x0726f0e2421adadf", "start_time": "2024-07-11T10:37:31.562540Z", "end_time": "2024-07-11T10:37:31.567137Z", "status": { "status_code": "UNSET" }, "attributes": { "jinja2.template_name": "random-pet-pic.html" }, "events": [], "links": [], "resource": { "attributes": { "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.25.0", "service.name": "hello-otel", "telemetry.auto.version": "0.46b0" }, "schema_url": "" } }
Automatic instrumentation is broadly scoped; in this case, you notice it generates things like trace_id
, span_id
, telemetry.sdk.name
, and more. To get a deeper level of insight into our application we can manually create new spans or modify existing ones.
These examples use code from a Python application that you can explore in the provided hands-on workshop (linked at the beginning of the article).
What's Next?
This article explored the use of OpenTelemetry auto-instrumentation to enhance our insights into the functioning of our application.
We saw that the focus was rather broad when targeting applications with auto-instrumentation, so in the next article, we explore how to gain better insights by adding manual instrumentation to our application leveraging the existing auto-instrumentation.
Published at DZone with permission of Eric D. Schabell, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments