• English日本語한국어
  • Log inStart now

OpenTelemetry tutorials: Instrument a sample Python app

Try out any of these Python tutorials to see what the New Relic platform can do with your OTLP data. We have three tutorials you can choose from, each one using the same demo Flask app. The app will calculate the nth number in the Fibonacci sequence and generate traces, metrics, and logs.

By working through these tutorials, you can learn skills to help you set up your own app with OpenTelemetry and New Relic.

After you finish any of these tutorials, you can view span metrics in charts like these.

While each tutorial uses the same demo app, they have different approaches to help you become acquainted with OpenTelemetry and New Relic. Try out the options that are interesting to you:

  • Tutorial 1: Run the pre-instrumented demo app: This is the fastest way to send some demo data to New Relic and see how it is displayed in the UI. In this tutorial, the demo app has pre-loaded instrumentation and SDK configurations that follow our best practices to generate and export metrics, logs, and traces. You can inspect our code and apply relevant sections to your own apps.
  • Tutorial 2: Monitor the demo app with the OpenTelemetry Python agent: Instead of using our pre-instrumented demo app, you can use the OpenTelemetry Python agent to automatically monitor our demo app. You don't need to open the demo code and make any changesjust install and run the agent alongside the app.
  • Tutorial 3: Set up the demo app manually: In this track, you'll roll up your sleeves and tinker with the engine of the car. This is the approach to take if you want to have the most control over what telemetry is reported and want to see details about how it's done. You'll manually insert instrumentation into our demo app to capture telemetry and you'll configure the SDK to export that data to New Relic.

Tip

You have two choices for exporting data from your application to New Relic via OTLP:

  • Directly from your app
  • Via an OpenTelemetry collector

This guide covers the first option. If you wish to export your data via a collector, check out this collector documentation for details.

Requirements

Before you get started, make sure you have the following:

Tutorial 1: Run the pre-instrumented demo app

This is a great option if you want us to do the instrumentation so you can quickly see what's it's like to send data to New Relic and view it in our UI.

  1. In your terminal, run the following to clone the demo app and navigate to the Getting Started Guides' python/Instrumented directory.

    git clone https://github.com/newrelic/newrelic-opentelemetry-examples.git
    cd newrelic-opentelemetry-examples/getting-started-guides/python/Instrumented
  2. Set these environment variables to send data to your New Relic account:

    • Make sure to use your .

    • If your New Relic data center region is EU and not US, set the endpoint to: https://otlp.eu01.nr-data.net

      • OTEL_EXPORTER_OTLP_HEADERS=api-key=INSERT_YOUR_NEW_RELIC_LICENSE_KEY
      • OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net
  3. Set this environment variable to name the service; this is how you will identify your service in your New Relic account:

    • OTEL_SERVICE_NAME=getting-started-python
  4. In the same getting-started-guides/python/Instrumented/ directory, create and activate a virtual environment, install the required libraries, and run the app:

    • macOS:

      python3 -m venv venv
      source venv/bin/activate
      pip install -r requirements.txt
      python3 app.py
    • PowerShell:

      python -m venv venv
      .\venv\Scripts\Activate.ps1
      pip install -r requirements.txt
      python app.py
  5. Open a new terminal tab, switch to the getting-started-guides/python/Instrumented directory, and run the following command to generate some traffic to the application:

    • macOS:
      ./load-generator.sh
    • PowerShell:
      .\load-generator.ps1

    Tip

    Alternatively, you can reach the endpoint in the browser at this URL: http://localhost:8080/fibonacci?n=INSERT_A_VALUE. Replace INSERT_A_VALUE with a value from 1 to 90. To generate an error, insert an integer outside the valid range.

  6. Go to one.newrelic.com > All capabilities > APM & services.

  7. Click your new entity (service) called getting-started-python and explore the UI. For more tips about what to look for in the UI, see View your data in New Relic.

  8. When you're finished looking at your data in the UI, shut down the application by pressing CONTROL+C in both terminal sessions.

Tutorial 2: Monitor the demo app with the OpenTelemetry Python agent

Here's a different tutorial that also uses the same demo app, but in this case, you'll use the OpenTelemetry Python agent to automatically monitor the demo app. You don't need to modify the Python source code. By using the agent, you can quickly start exporting sample data to New Relic.

Note, however, that you will need to add custom instrumentation to capture deeper levels of information about the app, such as logs and custom metrics.

The auto-instrumentation agent is a series PyPI package that dynamically injects bytecode to capture telemetry from popular libraries and frameworks. You can also use it to capture data such as inbound requests, outbound HTTP calls, and database calls. It can be attached to any Python 3 application.

Tip

See the official OpenTelemetry Python agent documentation for additional configuration options.

To monitor our demo app with the OpenTelemetry Python agent:

  1. Execute these two commands to download the demo application repository and change to the following directory:

    git clone https://github.com/newrelic/newrelic-opentelemetry-examples.git
    cd newrelic-opentelemetry-examples/getting-started-guides/python/Uninstrumented
  2. Go to our environment variables reference section below to see which variables you need to export and then return to these steps.

  3. Then, in the same getting-started-guides/python/Uninstrumented/ directory, create and activate a virtual environment:

    • macOS:

      python3 -m venv venv
      source venv/bin/activate
    • PowerShell:

      python -m venv venv
      .\venv\Scripts\Activate.ps1
  4. You are now ready to install the required libraries:

    pip install flask
    pip install opentelemetry-instrumentation-flask
    pip install opentelemetry-exporter-otlp
    pip install opentelemetry-distro
  5. Continue in getting-started-guides/python/Uninstrumented/ to launch the agent with the app:

    • macOS:
      opentelemetry-instrument python3 app.py
    • PowerShell:
      opentelemetry-instrument python app.py
  6. Generate traffic to the application by opening a new terminal in the getting-started-guides/python/Uninstrumented directory and running the load generator:

    • macOS:
      ./load-generator.sh
    • PowerShell:
      .\load-generator.ps1

      Tip

      Alternatively, you can reach the endpoint in the browser at this URL: http://localhost:8080/fibonacci?n=INSERT_A_VALUE. Replace INSERT_A_VALUE with a value from 1 to 90. To generate an error, insert an integer outside the valid range.

  7. Now that you've sent some data to New Relic, see our instructions on viewing the data in the UI.

  8. When you're finished looking at your data in the UI, shut down the application by pressing CONTROL+C in both terminal sessions.

Tutorial 3: Set up the demo app manually

The previous section helped you explore automatic instrumentation with the OpenTelemetry Python agent. If you prefer to have more control over the telemetry you gather, you can try out this tutorial to learn how to add custom instrumentation. Then, you'll see how to configure the OpenTelemetry SDK to export the data to New Relic, using our recommended best practices.

Here are the steps you'll complete for this manual setup:

A. Download the demo application

Run the following to download our demo app:

git clone https://github.com/newrelic/newrelic-opentelemetry-examples.git

B. Install required libraries

To add the required libraries:

  1. Go to the application directory for the uninstrumented app as the starting point for this tutorial. By the end of this tutorial, the code should look like the one in the Instrumented directory.

    cd newrelic-opentelemetry-examples/getting-started-guides/python/Uninstrumented
  2. Create and activate a virtual environment in the Uninstrumented directory:

    • macOS:

      python3 -m venv venv
      source venv/bin/activate
    • PowerShell:

      python -m venv venv
      .\venv\Scripts\Activate.ps1
  3. Install the following:

    pip install opentelemetry-api
    pip install opentelemetry-sdk
    pip install flask
    pip install opentelemetry-instrumentation-logging
    pip install opentelemetry-instrumentation-flask
    pip install opentelemetry-exporter-otlp
    pip install opentelemetry-distro

C. Configure the SDK

  1. In app.py, add the highlighted lines below to the top of the file. Change the value for the custom attribute environment as needed.
##########################
# OpenTelemetry Settings #
##########################
from opentelemetry.sdk.resources import Resource
import uuid
OTEL_RESOURCE_ATTRIBUTES = {
"service.instance.id": str(uuid.uuid1()),
"environment": "local"
}
from flask import Flask, jsonify, request
app = Flask(__name__)
  1. Go to our environment variables reference section below to see which variables you need to export, and then move forward to the next step to add instrumentation libraries.

D. Add instrumentation libraries: traces

In app.py, insert the following after the OpenTelemetry Settings you added:

##########
# Traces #
##########
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.trace.status import Status, StatusCode
# Initialize tracing and an exporter that can send data to an OTLP endpoint
# SELECT * FROM Span WHERE instrumentation.provider='opentelemetry'
trace.set_tracer_provider(TracerProvider(resource=Resource.create(OTEL_RESOURCE_ATTRIBUTES)))
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))

E. Add instrumentation libraries: metrics

In app.py add the following after the Traces section you added in Step D:

###########
# Metrics #
###########
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
# Initialize metering and an exporter that can send data to an OTLP endpoint
# SELECT count(`http.server.active_requests`) FROM Metric FACET `service.name` TIMESERIES
metrics.set_meter_provider(MeterProvider(resource=Resource.create(OTEL_RESOURCE_ATTRIBUTES), metric_readers=[PeriodicExportingMetricReader(OTLPMetricExporter())]))
metrics.get_meter_provider()
fib_counter = metrics.get_meter("opentelemetry.instrumentation.custom").create_counter("fibonacci.invocations", unit="1", description="Measures the number of times the fibonacci method is invoked.")

F. Add instrumentation libraries: logs

In app.py, add the following after the Metrics section. This will import the logging module and set the basicConfig logging level to DEBUG:

########
# Logs # - OpenTelemetry Logs are still in the experimental state, so function names may change in the future
########
import logging
logging.basicConfig(level=logging.DEBUG)
from opentelemetry import _logs
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
# Initialize logging and an exporter that can send data to an OTLP endpoint by attaching OTLP handler to root logger
# SELECT * FROM Log WHERE instrumentation.provider='opentelemetry'
_logs.set_logger_provider(LoggerProvider(resource=Resource.create(OTEL_RESOURCE_ATTRIBUTES)))
logging.getLogger().addHandler(LoggingHandler(logger_provider=_logs.get_logger_provider().add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter()))))

G. Add Flask instrumentation

In app.py add the highlighted lines below, after the Logs section. This helps with linking spans for distributed tracing and logs-in-context:

#####################
# Flask Application #
#####################
from flask import Flask, jsonify, request
from opentelemetry.instrumentation.flask import FlaskInstrumentor
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)

H. Custom trace instrumentation: Create a custom span

You can create whatever spans you want, and it is up to you to annotate your spans with attributes on specific operations. The attributes you set will provide additional context about the specific operation you are tracking, such as results or operation properties.

In app.py, insert the highlighted lines below to start a new span called /fibonacci that does the following:

  • Captures data about the execution of this method

  • Sets an attribute that stores the value of n from the user's request

    @app.route("/fibonacci")
    @trace.get_tracer("opentelemetry.instrumentation.custom").start_as_current_span("/fibonacci")
    def fibonacci():
    args = request.args
    x = int(args.get("n"))
    error_message = "n must be 1 <= n <= 90."
    trace.get_current_span().set_attribute("fibonacci.n", x)
    try:
    assert 1 <= x <= 90
    array = [0, 1]
    for n in range(2, x + 1):
    array.append(array[n - 1] + array[n - 2])
    trace.get_current_span().set_attribute("fibonacci.result", array[x])
    return jsonify(n=x, result=array[x])
    except AssertionError:
    return jsonify({"message": error_message})
    app.run(host='0.0.0.0', port=8080)

I. Custom trace instrumentation: Record an exception

You may want to record exceptions as they happen. We recommend you do this in conjunction with setting the span status.

  1. To set the span's status code to ERROR when an exception occurs, we also need to import the Status and StatusCode modules from the opentelemetry.trace.status package. Add the highlighted line below to the Traces section with the other traces libraries:
##########
# Traces #
##########
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.trace.status import Status, StatusCode
  1. Next, insert the highlighted lines below to record the exception, which will show up as a span event in New Relic, and set the span status to ERROR:
@app.route("/fibonacci")
@trace.get_tracer("opentelemetry.instrumentation.custom").start_as_current_span("/fibonacci")
def fibonacci():
args = request.args
x = int(args.get("n"))
error_message = "n must be 1 <= n <= 90."
trace.get_current_span().set_attribute("fibonacci.n", x)
try:
assert 1 <= x <= 90
array = [0, 1]
for n in range(2, x + 1):
array.append(array[n - 1] + array[n - 2])
trace.get_current_span().set_attribute("fibonacci.result", array[x])
return jsonify(n=x, result=array[x])
except AssertionError:
trace.get_current_span().record_exception(exception=Exception, attributes={"exception.type": "AssertionError", "exception.message": error_message})
trace.get_current_span().set_status(Status(StatusCode.ERROR, error_message))
return jsonify({"message": error_message})
app.run(host='0.0.0.0', port=8080)

J. Custom metric instrumentation: Add a custom metric counter

Metrics are a telemetry data type that are really helpful because they combine individual measurements into aggregations, and produce data that is constant as a function of system load. You can use this data in conjunction with spans to help spot trends and provide application runtime telemetry. You can also annotate any metric with attributes to help describe what subdivision of the measurements the metric represents.

The OpenTelemetry metrics API defines a number of instruments, which record measurements that are aggregated by the metrics SDK and exported out of process. There are two types of instruments:

  • Synchronous: These instruments record measurements as they occur
  • Asynchronous: These instruments register a callback, which is invoked only once per collection and do not have associated context
  1. In app.py, add the highlighted line below in the Metrics section to create a counter:
###########
# Metrics #
###########
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
# Initialize metering and an exporter that can send data to an OTLP endpoint
# SELECT count(`http.server.active_requests`) FROM Metric FACET `service.name` TIMESERIES
metrics.set_meter_provider(MeterProvider(resource=Resource.create(OTEL_RESOURCE_ATTRIBUTES), metric_readers=[PeriodicExportingMetricReader(OTLPMetricExporter())]))
metrics.get_meter_provider()
fib_counter = metrics.get_meter("opentelemetry.instrumentation.custom").create_counter("fibonacci.invocations", unit="1", description="Measures the number of times the fibonacci method is invoked.")
  1. Next, add the highlighted lines below to use the counter you just created to measure:
  • The number of times this function runs successfully
  • The number times it fails to run

Note that the counter will reset to 0 every time you restart your app.

@app.route("/fibonacci")
@trace.get_tracer("opentelemetry.instrumentation.custom").start_as_current_span("/fibonacci")
def fibonacci():
args = request.args
x = int(args.get("n"))
error_message = "n must be 1 <= n <= 90."
trace.get_current_span().set_attribute("fibonacci.n", x)
try:
assert 1 <= x <= 90
array = [0, 1]
for n in range(2, x + 1):
array.append(array[n - 1] + array[n - 2])
trace.get_current_span().set_attribute("fibonacci.result", array[x])
fib_counter.add(1, {"fibonacci.valid.n": "true"})
return jsonify(n=x, result=array[x])
except AssertionError:
trace.get_current_span().record_exception(exception=Exception, attributes={"exception.type": "AssertionError", "exception.message": error_message})
trace.get_current_span().set_status(Status(StatusCode.ERROR, error_message))
fib_counter.add(1, {"fibonacci.valid.n": "false"})
return jsonify({"message": error_message})
app.run(host='0.0.0.0', port=8080)

K. Custom log instrumentation

The status of the logs signal in OpenTelemetry Python is currently experimental.

In app.py, add the highlighted lines below to:

  • Record an INFO level log for the input and output values
  • Record an ERROR level log when the input value is outside of the valid range
@app.route("/fibonacci")
@trace.get_tracer("opentelemetry.instrumentation.custom").start_as_current_span("/fibonacci")
def fibonacci():
args = request.args
x = int(args.get("n"))
error_message = "n must be 1 <= n <= 90."
trace.get_current_span().set_attribute("fibonacci.n", x)
try:
assert 1 <= x <= 90
array = [0, 1]
for n in range(2, x + 1):
array.append(array[n - 1] + array[n - 2])
trace.get_current_span().set_attribute("fibonacci.result", array[x])
fib_counter.add(1, {"fibonacci.valid.n": "true"})
logging.info("Compute fibonacci(" + str(x) + ") = " + str(array[x]))
return jsonify(n=x, result=array[x])
except AssertionError:
trace.get_current_span().record_exception(exception=Exception, attributes={"exception.type": "AssertionError", "exception.message": error_message})
trace.get_current_span().set_status(Status(StatusCode.ERROR, error_message))
fib_counter.add(1, {"fibonacci.valid.n": "false"})
logging.error("Failed to compute fibonacci(" + str(x) + ")")
return jsonify({"message": error_message})
app.run(host='0.0.0.0', port=8080)

L. Exercise the app to generate some traffic

You're ready to send some data to New Relic!

  1. In the terminal, confirm that you're in the getting-started-guides/python/Uninstrumented directory, then run the application:

    • MacOS:
      python3 app.py
    • PowerShell:
      python app.py
  2. Generate traffic to the application by opening a new terminal tab in the getting-started-guides/python/Uninstrumented directory and running the load generator:

    • MacOS:
      ./load-generator.sh
    • PowerShell:
      .\load-generator.ps1

    Tip

    Alternatively, you can reach the endpoint in the browser at this URL: http://localhost:8080/fibonacci?n=INSERT_A_VALUE. Replace INSERT_A_VALUE with a value from 1 to 90. To generate an error, insert an integer outside the valid range.

  3. Now that you've sent some data to New Relic, see our instructions on viewing the data in the UI.

View your demo data in New Relic

No matter which tutorial you completed, you can follow the tips below for finding your data in the New Relic UI.

Note that if you followed Tutorial 2: Monitor the demo app with the OpenTelemetry Python agent:, you will not see the custom data (such as the custom metrics and logs), as you need to manually add custom instrumentation to capture more granular data.

  1. Go to one.newrelic.com > All capabilities > APM & services.
  2. Click your new entity (service) called getting-started-python (or whatever name you provided).
  3. Check out the details in the sections for each data type.

Tip

If you are using Microsoft Windows and do not see data in your New Relic account, check that you have allowed traffic through the firewall.

Traces

Once you've reached the getting-started-python entity in New Relic:

  1. In the left pane's Monitor section, click Distributed tracing, and then click the /fibonacci trace group.
  2. From there, find a trace with an error and click to open it:
  3. Once you have the trace open, click Show in-process spans, and then click on the resulting span, which will open up a details panel to the right. To see the exception you recorded when a user input is invalid, click on View span events:

If you completed the manual instrumentation tutorial, here's how the exception you recorded as a span will look in New Relic:

To view additional details that you set, such as the span attribute, span name, and status code, click on the Attributes tab. This pane is also where you can view additional metadata that is automatically collected by the instrumentation libraries you used in this guide, as well as metadata that is attached by New Relic:

For more details about viewing your data, see OpenTelemetry in the New Relic UI

Metrics

Once you've reached the getting-started-python entity in New Relic, you can see a list of all collected metrics, such as your custom counter attributes.

Metrics explorer

This is a tool that allows you to see a list of your metrics.

  1. In the left pane, select Data > Metrics explorer, and then select fibonacci.invocations.

  2. Under Dimensions, view the attributes you collected along with your custom metric, and then click on fibonacci.valid.n.

Learn more in our documentation about the metrics explorer view.

Logs

Here is where to access your logs:

You will also see logs in your terminal:

Back in your logs view, select a log, and you will see a pane open up with the log message and additional attributes that were collected, such as the associated span and trace ids, as well as metadata injected by New Relic:

You can navigate to the correlated distributed trace by clicking this little blue icon:

This will open a pane that displays the correlated trace, where you can view more details about the trace. For more about this page, see OpenTelemetry in the UI: Distributed tracing page and Understand and use the distributed tracing UI:

You can also find the correlated log from the distributed traces view. When you select a trace that has a corresponding log, you will see that indicated as a tab, and you can view the log directly from the trace without having to switch views:

Learn more about the logs view here.

Reference: Environment variables

This is a list of the environment variables you should export if you're doing tutorial 2 or 3. After you finish exporting the variables, return to the tutorials using the links that follow the variable list:

After you've exported the environment variables listed in the collapser above, return to the tutorial and complete the setup:

What's next?

Now that you've experimented with OpenTelemetry instrumentation and SDK configuration, you can apply what you've learned to set up your own app or service with OpenTelemetry and New Relic. For more, see Set up your own app or service with OpenTelemetry.

Copyright © 2024 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.