Are 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 Cruz.
The previous article introduced observability concepts and terms as 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 detect any needed libraries and exporter dependencies. In our demo application we are focusing on Python Flask and 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:
$ mkdir workshop-opentelemetry
$ cd workshop-opentelemetry
Download and unzip the following application project into your workshop directory from the following location:
Next we build the provided container image, presented here using Podman (feel free to substitute with Docker if desired), using the projects 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 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, opentelemetry-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]
RUN opentelemetry-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. Configures 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 \
--metrics_exporter none \
--service_name hello-otel \
flask run --host=0.0.0.0
* 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. There is more reading available for you on learning about the basics of OpenTelemetry.
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.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.