<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Louis Guitton</title>
    <description>The latest articles on DEV Community by Louis Guitton (@louisguitton).</description>
    <link>https://dev.to/louisguitton</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F47677%2Fce369d8a-0c29-43db-85ea-ce282b209852.jpeg</url>
      <title>DEV Community: Louis Guitton</title>
      <link>https://dev.to/louisguitton</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/louisguitton"/>
    <language>en</language>
    <item>
      <title>How to monitor your FastAPI service</title>
      <dc:creator>Louis Guitton</dc:creator>
      <pubDate>Sun, 08 Nov 2020 01:00:05 +0000</pubDate>
      <link>https://dev.to/louisguitton/how-to-monitor-your-fastapi-service-3mpo</link>
      <guid>https://dev.to/louisguitton/how-to-monitor-your-fastapi-service-3mpo</guid>
      <description>&lt;p&gt;&lt;em&gt;This article originally appeared on &lt;a href="https://guitton.co/posts/fastapi-monitoring/" rel="noopener noreferrer"&gt;https://guitton.co/posts/fastapi-monitoring/&lt;/a&gt;, head over there if you liked this post.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article, I'll discuss how to monitor the latency and code performance of a FastAPI service.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Monitoring vs API Profiling
&lt;/h2&gt;

&lt;p&gt;Monitoring is essentially &lt;strong&gt;collecting data in the background&lt;/strong&gt; of your application for the purpose of helping diagnosing issues, helping debugging errors, or informing on the latency of a service.&lt;/p&gt;

&lt;p&gt;For example, at the infrastructure level, you can monitor CPU and memory utilization. For example, at the application level, you can monitor errors, code performance or database querying performance. For a more complete introduction to monitoring and why it's necessary, see &lt;a href="https://www.fullstackpython.com/monitoring.html" rel="noopener noreferrer"&gt;this excellent post from Full Stack Python&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this post, we fill focus on &lt;strong&gt;Application Performance Monitoring (APM)&lt;/strong&gt; for a FastAPI application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Tracking
&lt;/h3&gt;

&lt;p&gt;In this post, I will not talk about monitoring application errors and warnings. For this purpose, check Sentry, it has great ASGI support and &lt;a href="https://docs.sentry.io/platforms/python/guides/asgi/" rel="noopener noreferrer"&gt;will work out of the box&lt;/a&gt; with your FastAPI service.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Profiling
&lt;/h3&gt;

&lt;p&gt;Profiling is a code best-practice that is not specific to web development. From the &lt;a href="https://docs.python.org/3/library/debug.html" rel="noopener noreferrer"&gt;python docs on profiling&lt;/a&gt; we can read :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the profilers run code and give you a detailed breakdown of execution times, allowing you to identify bottlenecks in your programs. Auditing events provide visibility into runtime behaviors that would otherwise require intrusive debugging or patching.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can of course apply profiling in the context of a FastAPI application. In which case you might find &lt;a href="https://fastapi-utils.davidmontague.xyz/user-guide/timing-middleware/" rel="noopener noreferrer"&gt;this timing middleware&lt;/a&gt; handy.&lt;/p&gt;

&lt;p&gt;However, with this approach, the timing data is logged to stdout. You can use it in development to to find bottlenecks, but in practice looking at the logs in production to get latency information is not the most convenient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available Tools for Application Performance Monitoring (APM)
&lt;/h2&gt;

&lt;p&gt;As will all things, there are many options. Some are open source, some are SaaS businesses.&lt;br&gt;
Most likely you or your organisation are already using one or more monitoring tools, so I'd suggest starting with the one you know.&lt;br&gt;
The tools on the list below don't do only APM, and that's what makes it harder to understand sometimes. Example application monitoring tools you might have heard of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.newrelic.com/docs/apm" rel="noopener noreferrer"&gt;New Relic&lt;/a&gt; (commercial with parts open source)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.datadoghq.com/tracing/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; (commercial with parts open source)&lt;/li&gt;
&lt;li&gt;StatsD (open source)&lt;/li&gt;
&lt;li&gt;Prometheus (open source)&lt;/li&gt;
&lt;li&gt;OpenTelemetry (open source)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This list is not exhaustive, but let's note &lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt;&lt;/a&gt; which is the&lt;br&gt;
most recent on this list and is now the de-facto standard for application monitoring metrics.&lt;/p&gt;

&lt;p&gt;At this point, choosing a tool doesn't matter, let's rather understand what an APM tool does.&lt;/p&gt;
&lt;h2&gt;
  
  
  The 4 Steps of Monitoring
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo0ypep1qt5znk873ghl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo0ypep1qt5znk873ghl3.png" title="The 4 components of monitoring" alt="4 steps of monitoring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It all starts with your application code. You instrument your
service with a library corresponding to your app's language
(in our case python). This is the &lt;code&gt;monitoring client library&lt;/code&gt;.
Monitoring client library examples:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/newrelic/newrelic-python-agent" rel="noopener noreferrer"&gt;newrelic/newrelic-python-agent: New Relic Python Agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DataDog/dd-trace-py" rel="noopener noreferrer"&gt;DataDog/dd-trace-py: Datadog Python APM Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-python" rel="noopener noreferrer"&gt;open-telemetry/opentelemetry-python: OpenTelemetry Python API and SDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Then the &lt;code&gt;monitoring client library&lt;/code&gt; sends each individual call to the &lt;code&gt;monitoring server daemon&lt;/code&gt; over the network (UDP in particular, as opposed to TCP or HTTP).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;monitoring server daemon&lt;/code&gt; is listening to monitoring events coming from the applications. It packs the incoming data into batches and regularly sends it to the &lt;code&gt;monitoring backend&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;monitoring backend&lt;/code&gt; has usually 2 parts: a data processing application and a visualisation webapp. It turns the stream of monitoring data into human-readable charts and alerts.&lt;br&gt;
Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app.datadoghq.com&lt;/li&gt;
&lt;li&gt;one.newrelic.com&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3zrrgk2ssvm1l6vrhsw7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3zrrgk2ssvm1l6vrhsw7.png" title="The 2 components of the monitoring backend" alt="monitoring backend"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem with monitoring ASGI webapps
&lt;/h2&gt;

&lt;p&gt;ASGI is a relatively new standard for python web servers. As with&lt;br&gt;
every new standard, &lt;strong&gt;it will take some time for all tools in the&lt;br&gt;
ecosystem to support it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Given the 4 steps of monitoring layed out above, a problem arise if&lt;br&gt;
the &lt;code&gt;monitoring client library&lt;/code&gt; doesn't support ASGI. For example,&lt;br&gt;
this is the case with NewRelic at the moment (see &lt;a href="https://github.com/newrelic/newrelic-python-agent/issues/5" rel="noopener noreferrer"&gt;ASGI - Starlette/Fast API Framework · Issue #5 · newrelic/newrelic-python-agent&lt;/a&gt; for more details). I looked at Datadog too and saw that ASGI is also not supported at the moment.&lt;/p&gt;

&lt;p&gt;On the open source side of the tools however, OpenTelemetry had&lt;br&gt;
great support for ASGI. So I set out to instrument my FastAPI&lt;br&gt;
service with OpenTelemetry.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update - Sep 19th, 2020:&lt;/em&gt;&lt;br&gt;
&lt;a href="http://pypi.datadoghq.com/trace/docs/web_integrations.html?highlight=asgi#asgi" rel="noopener noreferrer"&gt;There seems to be support for ASGI in ddtrace&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update - Sep 22th, 2020:&lt;/em&gt;&lt;br&gt;
&lt;a href="https://docs.newrelic.com/docs/agents/python-agent/python-agent-api/asgiapplication-python-agent-api" rel="noopener noreferrer"&gt;There is now an API in the NewRelic agent to support ASGI frameworks&lt;/a&gt;, with uvicorn already supported and starlette on the way.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update - Oct 23th, 2020:&lt;/em&gt;&lt;br&gt;
The NewRelic python agent now supports Starlette and FastAPI out of the box.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instrumenting FastAPI with OpenTelemetry and Jaeger
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry provides a standard for steps 1 (with &lt;code&gt;Instrumentors&lt;/code&gt;) and 2 (with &lt;code&gt;Exporters&lt;/code&gt;) from the 4 steps above. One of the big advantages of&lt;br&gt;
OpenTelemetry is that you can send the events to any monitoring&lt;br&gt;
backend (commercial or open source). This is especially &lt;strong&gt;awesome because you can use the same intrumentation setup for &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; environments&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that depending on the language you use for your microservice, your mileage may vary. For example,&lt;br&gt;
there is no NewRelic OpenTelemetry Exporter in Python yet.&lt;br&gt;
But there are OpenTelemetry Exporters for many others, see the list here: &lt;a href="https://opentelemetry.io/registry/" rel="noopener noreferrer"&gt;Registry | OpenTelemetry&lt;/a&gt; (filter by language and with type=Exporter).&lt;/p&gt;

&lt;p&gt;One of the available backends is &lt;a href="https://www.jaegertracing.io/" rel="noopener noreferrer"&gt;Jaeger: open source, end-to-end distributed tracing&lt;/a&gt;. (Note that Jaeger is also a monitoring client library that you can&lt;br&gt;
instrument your application with, but here that's not the part&lt;br&gt;
of interest).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh7c2aygfgcdj3limek3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh7c2aygfgcdj3limek3z.png" title="Example instrumentation" alt="opentelemetry jaeger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although it's open source and worked really easily, the issue I had with Jaeger was that &lt;strong&gt;it doesn't have any data pipeline yet&lt;/strong&gt;.&lt;br&gt;
This means that, in the visualisation webapp, you can browse traces&lt;br&gt;
but you cannot see any aggregated charts. Such a backend is &lt;a href="https://www.jaegertracing.io/roadmap/" rel="noopener noreferrer"&gt;on their roadmap&lt;/a&gt; though.&lt;/p&gt;

&lt;p&gt;Still, Jaeger is my goto tool for monitoring while in &lt;code&gt;development&lt;/code&gt;. See the last part for more details.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instrumenting FastAPI with OpenTelemetry and Datadog
&lt;/h2&gt;

&lt;p&gt;I couldn't find any open source monitoring backend with a data pipeline that would provide the features I was looking for&lt;br&gt;
(latency percentile plots, bar chart of total requests and errors ...).&lt;/p&gt;

&lt;p&gt;It became apparent that that's where commercial solutions like&lt;br&gt;
NewRelic and Datadog shine. I hence set out to try the OpenTelemtry Datadog exporter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fauxjn3rrocztykgalktv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fauxjn3rrocztykgalktv.png" title="Example instrumentation" alt="opentelemetry datadog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this approach, you get a fully featured monitoring backend&lt;br&gt;
that will allow you to have full observability for your microservice.&lt;/p&gt;

&lt;p&gt;The 2 drawbacks are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you need to deploy the Datadog agent yourself (with docker or on Kuberetes or on whatever environment fits your stack) and this can get a bit involved&lt;/li&gt;
&lt;li&gt;Datadog being a commercial product, this solution will not be free.
You will have to pay extra attention to the pricing of Datadog (especially if you deploy the Datadog
agent to Kubernetes 😈).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Example FastAPI instrumentation using OpenTelementry, Jaeger and DataDog
&lt;/h2&gt;

&lt;p&gt;So how does it look in the code ?&lt;br&gt;
This is how my application factory looks. If you have any questions, feel free to reach out on &lt;a href="https://twitter.com/louis_guitton" rel="noopener noreferrer"&gt;twitter&lt;/a&gt; or open a &lt;a href="https://github.com/louisguitton/guitton.co/issues" rel="noopener noreferrer"&gt;github issue&lt;/a&gt;.&lt;br&gt;
I will not share my instrumentation because it is specific to my application, but imagine that you can define any nested spans and that those traces will sent the same way to Jaeger or to DataDog. This makes it really fast to iterate on your instrumentation code (e.g. add or remove spans), and even faster to find performance bottlenecks in your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;FastAPI Application factory with OpenTelemetry instrumentation
sent to Jaeger in dev and to DataDog in staging and production.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.exporter.datadog&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DatadogExportSpanProcessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DatadogSpanExporter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.exporter.jaeger&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JaegerSpanExporter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.instrumentation.fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPIInstrumentor&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.sdk.trace&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TracerProvider&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.sdk.trace.export&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BatchExportSpanProcessor&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;my_api.config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;generate_settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;my_api.routers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;my_router_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_router_b&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Application factory.

    Returns:
        ASGI application to be passed to ASGI server like uvicorn or hypercorn.

    Reference:
    - [FastAPI Middlewares](https://fastapi.tiangolo.com/advanced/middleware/)
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# load application settings
&lt;/span&gt;    &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_settings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;development&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# opentelemetry + datadog for staging or production
&lt;/span&gt;        &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_tracer_provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TracerProvider&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;datadog_exporter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DatadogSpanExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;agent_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dd_trace_agent_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dd_service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dd_version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dd_tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_tracer_provider&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;add_span_processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nc"&gt;DatadogExportSpanProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datadog_exporter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# opentelemetry + jaeger for development
&lt;/span&gt;        &lt;span class="c1"&gt;# requires jaeger running in a container
&lt;/span&gt;        &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_tracer_provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TracerProvider&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;jaeger_exporter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JaegerSpanExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent_host_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6831&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_tracer_provider&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;add_span_processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;BatchExportSpanProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jaeger_exporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_export_batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My API&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Do something awesome, while being monitored.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Add your routers
&lt;/span&gt;    &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include_router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_router_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include_router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_router_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;FastAPIInstrumentor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instrument_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope that with this post you've learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the difference between profiling, monitoring, tracking errors&lt;/li&gt;
&lt;li&gt;the architecture of application monitoring&lt;/li&gt;
&lt;li&gt;some of application monitoring tools out there&lt;/li&gt;
&lt;li&gt;that OpenTelemetry allows you to reuse the same instrumentation setup for all your environments, which speeds up the speed at which you can find performance bottlenecks in your application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've used this setup to get a 10x speed up on one multi-lingual NLP fastapi service I built at OneFootball.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.datadoghq.com/blog/statsd/" rel="noopener noreferrer"&gt;StatsD, What It Is and How It Can Help You | Datadog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fullstackpython.com/monitoring.html" rel="noopener noreferrer"&gt;Monitoring - Full Stack Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.sentry.io/platforms/python/guides/asgi/" rel="noopener noreferrer"&gt;ASGI | Sentry Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/debug.html" rel="noopener noreferrer"&gt;Debugging and Profiling — Python 3.9.0 documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fastapi-utils.davidmontague.xyz/user-guide/timing-middleware/" rel="noopener noreferrer"&gt;Timing Middleware - FastAPI Utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.newrelic.com/docs/apm" rel="noopener noreferrer"&gt;APM | New Relic Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.datadoghq.com/tracing/" rel="noopener noreferrer"&gt;APM &amp;amp; Distributed Tracing - Datadog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/newrelic/newrelic-python-agent" rel="noopener noreferrer"&gt;newrelic/newrelic-python-agent: New Relic Python Agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DataDog/dd-trace-py" rel="noopener noreferrer"&gt;DataDog/dd-trace-py: Datadog Python APM Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-python" rel="noopener noreferrer"&gt;open-telemetry/opentelemetry-python: OpenTelemetry Python API and SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/registry/" rel="noopener noreferrer"&gt;Registry | OpenTelemetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jaegertracing.io/" rel="noopener noreferrer"&gt;Jaeger: open source, end-to-end distributed tracing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opentelemetry-python.readthedocs.io/en/stable/getting-started.html" rel="noopener noreferrer"&gt;Getting Started with OpenTelemetry Python — OpenTelemetry Python documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>monitoring</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
