DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • OpenTelemetry Moves Past the Three Pillars
  • The Cost of Knowing: When Observability Becomes the Outage
  • Seeing the Whole System: Why OpenTelemetry Is Ending the Era of Fragmented Visibility
  • Observability Without Cost Telemetry Is Broken Engineering

Trending

  • The Missing `bandit` for AI Agents: How I Built a Static Analyzer for Prompt Injection
  • Building a Spring AI Assistant With MCP Servers: A Step-by-Step Tutorial
  • Your AI Agent Tests Are Passing, But Your Agent Is Still Broken
  • Architecting Zero-Trust AI Agents: How to Handle Data Safely
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Monitoring and Observability
  4. A Hands-On Guide to OpenTelemetry: Better Tracing With Automatic Instrumentation

A Hands-On Guide to OpenTelemetry: Better Tracing With Automatic Instrumentation

This article continues the journey by learning the first steps in generating better tracing with automatic instrumentation.

By 
Eric D.  Schabell user avatar
Eric D. Schabell
DZone Core CORE ·
Paige Cruz user avatar
Paige Cruz
·
Jul. 30, 24 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
4.2K Views

Join the DZone community and get the full member experience.

Join For Free

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. 

In the previous article, we took our first steps in generating telemetry data using automatic instrumentation. In this article, we explore how to gain better insights by adding manual instrumentation to our application leveraging the existing auto-instrumentation.

It is assumed that you followed the previous articles in setting up both OpenTelemetry and the example Python application project, but if not, go back and see the previous articles as it's not covered here.

We saw that automatic instrumentation was very broadly scoped with our Python application, generating things like trace_id, span_id, telemetry.sdk.name, and more. To get a deeper level of insight into our application we need to manually create new spans or modify existing ones.

Manually Instrumenting Application

With our auto-instrumentation set up previously, one of the libraries opentelemetry-bootstrap installed was opentelemetry-instrumentation-flask. This library instruments web requests to the Flask application, so let's modify that a bit by adding the number of times the homepage has been loaded as an attribute on the auto-instrumented span.

Below is the current telemetry data output from loading the homepage, showing a single span from our console log with auto-instrumentation generating default attributes such as http.method, http.host, and more:

JSON
 
10.88.0.19 - - [11/Jul/2024 10:37:20] "GET / HTTP/1.1" 200 -
{
    "name": "GET /",
    "context": {
        "trace_id": "0xdd1f48a2740d5c133bd288333e99b176",
        "span_id": "0xa27a71b94664503f",
        "trace_state": "[]"
    },
    "kind": "SpanKind.SERVER",
    "parent_id": null,
    "start_time": "2024-07-11T10:37:20.904983Z",
    "end_time": "2024-07-11T10:37:20.917104Z",
    "status": {
        "status_code": "UNSET"
    },
    "attributes": {
        "http.method": "GET",
        "http.server_name": "0.0.0.0",
        "http.scheme": "http",
        "net.host.name": "localhost:8001",
        "http.host": "localhost:8001",
        "net.host.port": 8000,
        "http.target": "/",
        "net.peer.ip": "10.88.0.19",
        "net.peer.port": 37982,
        "http.user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
        "http.flavor": "1.1",
        "http.route": "/",
        "hits": 1,
        "http.status_code": 200
    },
    "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": ""
    }
}


Let's refine our insights by adding some telemetry data collection using the OpenTelemetry SDK which was installed by the call to opentelemetry-distro. We access this by importing the trace module as shown below as found in the project file automatic/app.py:

JSON
 
import random
import re
import urllib3

import requests
from opentelemetry import trace
from flask import Flask, render_template, request
...


This gives us access to the auto-instrumented spans through the tracer, which has been created by our agent wrapper opentelemetry-instrument. We just access it programmatically as shown below a little farther down in the project file:

JSON
 
import random
import re
import urllib3

import requests
from opentelemetry import trace
from flask import Flask, render_template, request
from breeds import breeds

app = Flask(__name__)
tracer = trace.get_tracer(app.name)
...


Through the auto-instrumentation our Flask routes are all instrumented, so we want to access those through existing spans and not create a new one. We continue down in the file where an attribute named hits in the method named index() under the homepage route is added to track page loads as shown below:

Shell
 
@app.route('/')
def index():
    span = trace.get_current_span()
    global HITS
    HITS = HITS + 1
    span.set_attribute("hits", HITS)
    msg = f'This webpage has been viewed {HITS} times'
    return msg


Once all these changes have been verified in the file automatic/app.py, then we build a new container image with the following command:

Shell
 
$ podman build -t hello-otel:auto-manual -f automatic/Buildfile-auto

Successfully tagged localhost/hello-otel:auto-manual  \
516c5299a32b68e7a4634ce15d1fd659eed2164ebe945ef1673f7a55630e22c8


When we run this container image we are again wrapping it with the OpenTelemetry agent, known as opentelemetry-instrument. 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:

Shell
 
$ podman run -i -p 8001:8000 -e FLASK_RUN_PORT=8000 hello-otel:auto-manual \
    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 to verify the new manual attribute in the existing span generated by auto-instrumentation. We do this by opening the main page at http://localhost:8001 in our browser examining the trace in our running container console log and locating the hits entry:

JSON
 
10.88.0.20 - - [12/Jul/2024 11:12:49] "GET / HTTP/1.1" 200 -
{
    "name": "GET /",
    "context": {
        "trace_id": "0x6dc306ffe9c6add8df597e8a18878bd6",
        "span_id": "0x4018ff1f2b51431d",
        "trace_state": "[]"
    },
    "kind": "SpanKind.SERVER",
    "parent_id": null,
    "start_time": "2024-07-12T11:12:49.077685Z",
    "end_time": "2024-07-12T11:12:49.081377Z",
    "status": {
        "status_code": "UNSET"
    },
    "attributes": {
        "http.method": "GET",
        "http.server_name": "0.0.0.0",
        "http.scheme": "http",
        "net.host.name": "localhost:8001",
        "http.host": "localhost:8001",
        "net.host.port": 8000,
        "http.target": "/",
        "net.peer.ip": "10.88.0.20",
        "net.peer.port": 37058,
        "http.user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...",
        "http.flavor": "1.1",
        "http.route": "/",


JSON
 
        "hits": 1, 
        "http.status_code": 200


These examples use code from a Python application that you can explore in the provided hands-on workshop. 

What's Next?

This article explored the use of OpenTelemetry auto-instrumentation and how to combine that automation with manual instrumentation to enhance our insights into the functioning of our application.

Next up, diving into programmatic instrumentation with OpenTelemetry.

Telemetry Attribute (computing) Instrumentation (computer programming)

Published at DZone with permission of Eric D. Schabell. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • OpenTelemetry Moves Past the Three Pillars
  • The Cost of Knowing: When Observability Becomes the Outage
  • Seeing the Whole System: Why OpenTelemetry Is Ending the Era of Fragmented Visibility
  • Observability Without Cost Telemetry Is Broken Engineering

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook