<?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: Cristian Spinetta</title>
    <description>The latest articles on DEV Community by Cristian Spinetta (@cspinetta).</description>
    <link>https://dev.to/cspinetta</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%2F407771%2Fc278de36-4215-46f6-8860-a8ae812db82e.jpg</url>
      <title>DEV Community: Cristian Spinetta</title>
      <link>https://dev.to/cspinetta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cspinetta"/>
    <language>en</language>
    <item>
      <title>A deadlock on an uncontended Tokio RwLock (caused by futures::executor::block_on)</title>
      <dc:creator>Cristian Spinetta</dc:creator>
      <pubDate>Mon, 09 Feb 2026 21:52:52 +0000</pubDate>
      <link>https://dev.to/cspinetta/a-deadlock-on-an-uncontended-tokio-rwlock-caused-by-futuresexecutorblockon-490i</link>
      <guid>https://dev.to/cspinetta/a-deadlock-on-an-uncontended-tokio-rwlock-caused-by-futuresexecutorblockon-490i</guid>
      <description>&lt;h2&gt;
  
  
  A weird test hang
&lt;/h2&gt;

&lt;p&gt;I recently hit a Rust test that hung forever:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no panic&lt;/li&gt;
&lt;li&gt;no error&lt;/li&gt;
&lt;li&gt;no timeout&lt;/li&gt;
&lt;li&gt;just… silence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The confusing part: the code path only used &lt;code&gt;tokio::sync::RwLock::read()&lt;/code&gt;. No writers, no contention. Two reads succeeded. The third &lt;code&gt;read().await&lt;/code&gt; never returned.&lt;/p&gt;

&lt;p&gt;That sounds impossible if you're thinking in "classic lock" terms.&lt;/p&gt;

&lt;p&gt;But the root cause wasn't contention. It was &lt;strong&gt;executor semantics&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The minimal reproducer
&lt;/h2&gt;

&lt;p&gt;I published a tiny repro repo that demonstrates the behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cargo run&lt;/code&gt; → hangs (expected)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cargo run -- --fixed&lt;/code&gt; → completes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/cspinetta/tokio-block-on-deadlock" rel="noopener noreferrer"&gt;tokio-block-on-deadlock&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repro intentionally forces Tokio's cooperative scheduler to yield, then attempts another uncontended read lock.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model mismatch
&lt;/h2&gt;

&lt;p&gt;A common assumption is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a lock is uncontended, acquiring it can't block.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's true for synchronous locks, but async is different. In async Rust, &lt;code&gt;.await&lt;/code&gt; means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Poll the future&lt;/li&gt;
&lt;li&gt;If it can't make progress &lt;em&gt;right now&lt;/em&gt;, return &lt;code&gt;Poll::Pending&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The executor will poll it again later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crucially:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Pending&lt;/code&gt; does not always mean "the resource isn't ready".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes it means "yield for fairness".&lt;/p&gt;

&lt;h2&gt;
  
  
  Tokio's cooperative scheduling (the key)
&lt;/h2&gt;

&lt;p&gt;Tokio uses &lt;strong&gt;cooperative scheduling&lt;/strong&gt;. Each task has a limited budget to prevent a single task from starving others.&lt;/p&gt;

&lt;p&gt;When that budget is exhausted, Tokio can intentionally return &lt;code&gt;Poll::Pending&lt;/code&gt; to force a yield — even if the underlying resource is available.&lt;/p&gt;

&lt;p&gt;Under a normal Tokio runtime, that's fine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the task gets re-polled&lt;/li&gt;
&lt;li&gt;the budget is reset&lt;/li&gt;
&lt;li&gt;the operation completes on the next poll&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is usually invisible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it goes wrong: &lt;code&gt;futures::executor::block_on&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In my case, I discovered that part of the test setup was driving Tokio async code using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;block_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a common pattern in tests/mocks when you have a synchronous callback but need to call async code.&lt;/p&gt;

&lt;p&gt;The problem is: &lt;strong&gt;&lt;code&gt;futures::executor::block_on&lt;/code&gt; is not the Tokio runtime.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What it does is roughly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Poll the future on the current OS thread&lt;/li&gt;
&lt;li&gt;If it returns &lt;code&gt;Pending&lt;/code&gt;, park the thread and wait for a wake-up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when Tokio returns &lt;code&gt;Pending&lt;/code&gt; for cooperative scheduling reasons, &lt;code&gt;block_on&lt;/code&gt; treats it as "I should sleep until someone wakes me".&lt;/p&gt;

&lt;p&gt;But in this scenario, there isn't a normal "external wake-up" to wait for. Tokio expected the runtime to re-poll the task.&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the OS thread parks&lt;/li&gt;
&lt;li&gt;the future never gets re-polled&lt;/li&gt;
&lt;li&gt;the test hangs forever&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the lock looks "deadlocked" even though it's uncontended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happened on the &lt;em&gt;third&lt;/em&gt; read
&lt;/h2&gt;

&lt;p&gt;Because the cooperative budget is cumulative.&lt;/p&gt;

&lt;p&gt;The first awaits didn't exhaust the budget. The third happened to be the first place where Tokio decided "you must yield now", returning &lt;code&gt;Pending&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With small code changes, the hang could move earlier/later or disappear entirely — which is part of what makes this class of bug hard to debug.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical fix
&lt;/h2&gt;

&lt;p&gt;The simplest rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If async code uses Tokio primitives, it must be driven by Tokio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you need to run async code from a synchronous context (tests/mocks/callbacks), one safe pattern is to drive it with Tokio's runtime handle on a separate OS thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;tokio_block_on&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;future&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Future&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;F&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;
    &lt;span class="nn"&gt;F&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.spawn&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="nf"&gt;.block_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the repro repo, &lt;code&gt;cargo run -- --fixed&lt;/code&gt; uses this approach and completes successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Poll::Pending&lt;/code&gt; doesn't always mean "waiting for a resource"&lt;/li&gt;
&lt;li&gt;Tokio relies on its runtime to re-poll tasks; mixing executors can break that assumption&lt;/li&gt;
&lt;li&gt;Avoid &lt;code&gt;futures::executor::block_on&lt;/code&gt; for Tokio tasks&lt;/li&gt;
&lt;li&gt;If you must cross sync/async boundaries, drive futures using Tokio itself (or redesign the boundary)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This bug is rare, but it sits in a very common pattern: sync test/mocking glue calling async code. When it happens, it's deeply confusing — and completely silent.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>tokio</category>
      <category>async</category>
      <category>testing</category>
    </item>
    <item>
      <title>Kafka lag exporter Standalone</title>
      <dc:creator>Cristian Spinetta</dc:creator>
      <pubDate>Thu, 23 Jul 2020 19:42:56 +0000</pubDate>
      <link>https://dev.to/cspinetta/kafka-lag-exporter-standalone-1jbj</link>
      <guid>https://dev.to/cspinetta/kafka-lag-exporter-standalone-1jbj</guid>
      <description>&lt;p&gt;To research and diagnose issues of &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Apache Kafka&lt;/a&gt; consumer groups I usually use a docker compose made up of &lt;a href="https://github.com/lightbend/kafka-lag-exporter" rel="noopener noreferrer"&gt;Kafka Lag Exporter&lt;/a&gt;, &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt;, &lt;a href="https://grafana.com/" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt; and a &lt;a href="https://github.com/lightbend/kafka-lag-exporter/tree/master/grafana" rel="noopener noreferrer"&gt;Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the repo:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cspinetta" rel="noopener noreferrer"&gt;
        cspinetta
      &lt;/a&gt; / &lt;a href="https://github.com/cspinetta/kafka-lag-exporter-standalone" rel="noopener noreferrer"&gt;
        kafka-lag-exporter-standalone
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Docker Compose with Kafka Lag Exporter + Grafana + Prometheus. Ready to ingest and viewing lag metrics.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In this post I want to tell you what it is about and how it can be useful for troubleshooting in case you don't have much visibility of your Kafka consumer groups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this docker compose?
&lt;/h3&gt;

&lt;p&gt;The main idea was to have a docker compose with &lt;a href="https://github.com/lightbend/kafka-lag-exporter" rel="noopener noreferrer"&gt;Kafka Lag Exporter&lt;/a&gt;, &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt; and &lt;a href="https://grafana.com/" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt; together, so that it can be &lt;strong&gt;quick&lt;/strong&gt; and &lt;strong&gt;easy&lt;/strong&gt; to get a dashboard for analyzing the consumer groups of a Kafka deployment. This is particularly useful when you don't have enough monitoring on your Kafka yet. If we had not made a docker compose, we would have to install and configure each part separately, which could be a bit cumbersome when faced with an incident that needs to be resolved quickly.&lt;/p&gt;

&lt;p&gt;It aims to provide a quick installation for troubleshooting and not a final installation for permanent monitoring. It's perfect if you are facing an issue in production and need more visibility about what is happening internally in Kafka.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example use cases
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Consumer group lag in seconds
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjax18tlj4zesw7jsgkz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjax18tlj4zesw7jsgkz2.png" alt="Consumer Groups Time Lag" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this graph we can see the time between last commit and current time, this is also known as lag in seconds, and we can see it by consumer group.&lt;/p&gt;

&lt;p&gt;This example was taken from a &lt;code&gt;Kafka-Connect&lt;/code&gt; that commits every 30 minutes if everything goes well, if we analyze it we can say that some consumer groups by some reason fail on commit.&lt;/p&gt;

&lt;h4&gt;
  
  
  Consumers group lag in seconds and offsets
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdig6tfkebbngs1le7ynb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdig6tfkebbngs1le7ynb.png" alt="Consumer Group Time and Events Lag" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this other example, we can see a particular consumer group status. It shows the consumer group lag in seconds and messages/events (the difference between current message and last commited)&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;p&gt;Next, the steps we do when we have to use it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download and unpack it:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; kafka-lag-exporter-standalone.tar.gz https://github.com/cspinetta/kafka-lag-exporter-standalone/releases/download/0.0.1/kafka-lag-exporter-standalone-0.0.1.tar
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xf&lt;/span&gt; kafka-lag-exporter-standalone.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Specify kafka nodes on &lt;a href="//kafka-exporter-standalone/kafka-lag-exporter/application.conf"&gt;kafka-exporter-standalone/kafka-lag-exporter/application.conf&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run with docker compose: &lt;code&gt;docker-compose -f kafka-exporter-standalone/docker-compose.yaml up&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then you can open the Grafana webapp exposed at port &lt;code&gt;3000&lt;/code&gt; and navigate to the dashboard &lt;strong&gt;Kafka Lag Exporter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the first time you enter Grafana ask you to login. Type &lt;code&gt;admin&lt;/code&gt; for the username and password. Then Grafana will ask you to choose a new password.&lt;/p&gt;

&lt;p&gt;That's all!&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>monitoring</category>
      <category>troubleshooting</category>
      <category>devops</category>
    </item>
    <item>
      <title>top-threads: a script for viewing real-time runqueue latency per thread</title>
      <dc:creator>Cristian Spinetta</dc:creator>
      <pubDate>Wed, 22 Jul 2020 14:29:15 +0000</pubDate>
      <link>https://dev.to/cspinetta/top-threads-real-time-runqueue-latency-per-thread-1cpc</link>
      <guid>https://dev.to/cspinetta/top-threads-real-time-runqueue-latency-per-thread-1cpc</guid>
      <description>&lt;p&gt;A few years ago, when I was working at &lt;a href="https://dev.toArgentina"&gt;Despegar&lt;/a&gt; I wrote a little &lt;code&gt;python&lt;/code&gt; script that helped me a lot observing and identifying issues related to CPU usage.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cspinetta" rel="noopener noreferrer"&gt;
        cspinetta
      &lt;/a&gt; / &lt;a href="https://github.com/cspinetta/top-threads" rel="noopener noreferrer"&gt;
        top-threads
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A tiny command line tool that provides a dynamic real-time view of the active threads for a given process with stats of CPU, disk and scheduling.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It's a user-friendly command-line interface that provides a dynamic real-time view of the active threads for a given process with stats of CPU, disk and &lt;em&gt;scheduling&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The metrics make it really powerful is those related to scheduling: time spent on the cpu / on the runqueue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;In some cases it's interesting to know how much time the threads spend &lt;em&gt;trying to get onto CPU&lt;/em&gt;, instead of &lt;em&gt;being on CPU&lt;/em&gt;. This type of information can be easily obtained with tracing tools like &lt;a href="https://perf.wiki.kernel.org/index.php/Main_Page" rel="noopener noreferrer"&gt;perf&lt;/a&gt; and &lt;a href="https://github.com/iovisor/bcc" rel="noopener noreferrer"&gt;BCC&lt;/a&gt;, but these tools require &lt;em&gt;root privilege&lt;/em&gt;, something that is often not available in production servers, so you can't use them for troubleshooting.&lt;/p&gt;

&lt;h3&gt;
  
  
  What came up?
&lt;/h3&gt;

&lt;p&gt;I ended up developing a script in &lt;code&gt;Python&lt;/code&gt; that allows me to visualize in real-time &lt;em&gt;the run queue latency per task&lt;/em&gt; by reading the &lt;a href="https://www.kernel.org/doc/html/latest/scheduler/sched-stats.html#proc-pid-schedstat" rel="noopener noreferrer"&gt;/proc/{pid}/schedstat&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;In fact, it shows some extra stats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU usage: &lt;em&gt;total&lt;/em&gt;, &lt;em&gt;%usr&lt;/em&gt;, &lt;em&gt;%system&lt;/em&gt;, &lt;em&gt;%guest&lt;/em&gt; and &lt;em&gt;%wait&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Disk usage: kB read per second and kB written per second&lt;/li&gt;
&lt;li&gt;Scheduler stats:

&lt;ul&gt;
&lt;li&gt;time spent on the cpu.&lt;/li&gt;
&lt;li&gt;time spent waiting on a run queue (&lt;em&gt;runqueue latency&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;number of &lt;em&gt;timeslices&lt;/em&gt; run on the current CPU.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Java details: in case the target is a Java process that can be attached with &lt;code&gt;jstack&lt;/code&gt;, some extra details is shown such as thread name and stack traces.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;It requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Python 3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sysstat/sysstat" rel="noopener noreferrer"&gt;systat&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It only works in &lt;code&gt;Linux&lt;/code&gt; since it uses &lt;a href="https://www.kernel.org/doc/html/latest/scheduler/sched-stats.html#proc-pid-schedstat" rel="noopener noreferrer"&gt;/proc/{pid}/schedstat&lt;/a&gt; to get scheduling stats.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use it?
&lt;/h3&gt;

&lt;p&gt;I kept the code in a single file, so it's as easy as downloading the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-O&lt;/span&gt; top_threads.py &lt;span class="s1"&gt;'https://github.com/cspinetta/top-threads/releases/download/0.0.1/top_threads.py'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chmod&lt;/span&gt; +x top_threads.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example of usages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# watch &amp;lt;pid&amp;gt;'s threads with default values&lt;/span&gt;
./top_threads.py &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;pid&amp;gt;

&lt;span class="c"&gt;# print output in the terminal&lt;/span&gt;
./top_threads.py &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;pid&amp;gt; &lt;span class="nt"&gt;--display&lt;/span&gt; terminal

&lt;span class="c"&gt;# sorting by run queue latency&lt;/span&gt;
./top_threads.py &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;pid&amp;gt; &lt;span class="nt"&gt;--sort&lt;/span&gt; rq

&lt;span class="c"&gt;# in case a java process, change the number of stack traces to display&lt;/span&gt;
./top_threads.py &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;pid&amp;gt; &lt;span class="nt"&gt;--max-stack-depth&lt;/span&gt; 10

&lt;span class="c"&gt;# enable debug log for troubleshooting&lt;/span&gt;
./top_threads.py &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;pid&amp;gt; &lt;span class="nt"&gt;--debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Some things to keep in mind:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first output is with stats from the first execution of the process.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--display refresh&lt;/code&gt; provides a view similar to &lt;code&gt;top&lt;/code&gt; or &lt;code&gt;watch&lt;/code&gt; (the default) while &lt;code&gt;terminal&lt;/code&gt; prints the output on each iteration in the terminal like &lt;code&gt;pidstat&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What is a good use case for this tool?
&lt;/h3&gt;

&lt;p&gt;I often use this script when I have to analyze a performance problem at thread level and I want to inspect the dynamic usage of CPU or Disk.&lt;/p&gt;

&lt;p&gt;Some questions this tool helps me to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which thread is eating the entire CPU?&lt;/li&gt;
&lt;li&gt;How long are the threads waiting to take the CPU?&lt;/li&gt;
&lt;li&gt;What threads are using the disk right now?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example in pictures
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;--display refresh&lt;/code&gt; (the default):&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F228lkptniqw0jp8syx49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F228lkptniqw0jp8syx49.png" alt="Top Java Threads Refresh" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;--display terminal&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr3pbcs11uzd1d4okvjds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr3pbcs11uzd1d4okvjds.png" alt="Top Java Threads in Terminal" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usage: top_threads.py &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-h&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; PID &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;NUMBER]]
                      &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--max-stack-depth&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;STACK_SIZE]]
                      &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--sort&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;cpu,rq,disk,disk-rd,disk-wr&lt;span class="o"&gt;}]]&lt;/span&gt;
                      &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--display&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;terminal,refresh&lt;span class="o"&gt;}]]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--no-jstack&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--debug&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

Tool &lt;span class="k"&gt;for &lt;/span&gt;analysing active Threads

optional arguments:
  &lt;span class="nt"&gt;-h&lt;/span&gt;, &lt;span class="nt"&gt;--help&lt;/span&gt;            show this &lt;span class="nb"&gt;help &lt;/span&gt;message and &lt;span class="nb"&gt;exit&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; PID                Process ID
  &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;NUMBER]           Number of threads to show per sample. Default: 10
  &lt;span class="nt"&gt;--max-stack-depth&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;STACK_SIZE], &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;STACK_SIZE]
                        Max number of stack frames &lt;span class="o"&gt;(&lt;/span&gt;only when jstack can be
                        used&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; Default: 1
  &lt;span class="nt"&gt;--sort&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;cpu,rq,disk,disk-rd,disk-wr&lt;span class="o"&gt;}]&lt;/span&gt;, &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;cpu,rq,disk,disk-rd,disk-wr&lt;span class="o"&gt;}]&lt;/span&gt;
                        Field used &lt;span class="k"&gt;for &lt;/span&gt;sorting. Default: cpu
  &lt;span class="nt"&gt;--display&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;terminal,refresh&lt;span class="o"&gt;}]&lt;/span&gt;, &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;terminal,refresh&lt;span class="o"&gt;}]&lt;/span&gt;
                        Select the way to display the info: terminal or
                        refresh. Default: refresh
  &lt;span class="nt"&gt;--no-jstack&lt;/span&gt;           Turn off usage of jstack to retrieve thread info like
                        name and stack
  &lt;span class="nt"&gt;--debug&lt;/span&gt;               Turn on logs &lt;span class="k"&gt;for &lt;/span&gt;debugging purposes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>troubleshooting</category>
      <category>performance</category>
      <category>linux</category>
      <category>observability</category>
    </item>
    <item>
      <title>Monitoring Production Methodologically (Talk with the transcript)</title>
      <dc:creator>Cristian Spinetta</dc:creator>
      <pubDate>Tue, 21 Jul 2020 01:17:30 +0000</pubDate>
      <link>https://dev.to/cspinetta/monitoring-production-methodologically-talk-with-the-transcript-3m5f</link>
      <guid>https://dev.to/cspinetta/monitoring-production-methodologically-talk-with-the-transcript-3m5f</guid>
      <description>&lt;h1&gt;
  
  
  Versión en Español
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/dpsoft/monitoring-production-methodologically-talk-with-transcript-80g"&gt;(English version)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fecha: 11/06/2020&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Autores:&lt;/em&gt; &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__338612"&gt;
    &lt;a href="/dpsoft" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F338612%2F8c19892e-3f84-42d3-8185-62f8b57fa1de.png" alt="dpsoft image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/dpsoft"&gt;Diego&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/dpsoft"&gt;Software engineer from Buenos Aires, currently interested in performance and distributed systems.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__407771"&gt;
    &lt;a href="/cspinetta" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F407771%2Fc278de36-4215-46f6-8860-a8ae812db82e.jpg" alt="cspinetta image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/cspinetta"&gt;Cristian Spinetta&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/cspinetta"&gt;Software engineer working on distributed systems, reliability, and applied cryptography. Opinions are my own.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Esta es una transcripción &lt;em&gt;editada&lt;/em&gt; y &lt;em&gt;sintetizada&lt;/em&gt; de la charla &lt;a href="https://slides.com/diegoparra/monitoring-production-methodologically/" rel="noopener noreferrer"&gt;Monitoring Production Methodologically&lt;/a&gt; que dimos en &lt;a href="https://www.linkedin.com/company/despegarcom/" rel="noopener noreferrer"&gt;Despegar&lt;/a&gt; el 11 de Junio del 2020. En los últimos 5 años hemos trabajado juntos en diferentes proyectos como desarrolladores, y en el camino, hemos investigado y probado diferentes herramientas y técnicas para monitorear las apps. Esta charla, incluye muchas lecciones y técnicas aprendidas durante estos años.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transcripción:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjdspj7a7ct0ivez0e1ch.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjdspj7a7ct0ivez0e1ch.jpg" alt="Slide 01" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esta es una charla sobre los aspectos a tener en cuenta a la hora de armar nuestro sistema de monitoreo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxeetnto4j4b8xxxoxfly.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxeetnto4j4b8xxxoxfly.jpg" alt="Slide 02" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estas son algunas de las preguntas que queremos responder. Intentaremos ahondar el tema desde un punto de vista práctico. Si bien mostraremos ejemplos con algunas herramientas concretas, el foco estará en hablar sobre los lineamientos y aspectos a tener en cuenta, no en qué herramienta podemos usar.&lt;/p&gt;

&lt;p&gt;Las ideas que vamos a compartir son &lt;em&gt;aspiracionales&lt;/em&gt;, es decir, lineamientos que creemos que sirven de guía para lograr un sistema de monitoreo exitoso. Luego cada uno tendrá que analizar y decidir cuál es la forma más conveniente de bajarlo a su propio sistema.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi6ulg4k8h9uostxk76xd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi6ulg4k8h9uostxk76xd.jpg" alt="Slide 03" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjspccz7ha25ei29625vj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjspccz7ha25ei29625vj.jpg" alt="Slide 04" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En algún momento seguramente nos hicimos preguntas como estas, que fueron disparadores para empezar a pensar cómo construir o elegir un sistema de monitoreo para nuestras aplicaciones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy6pq1dov33ol36jo9woy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy6pq1dov33ol36jo9woy.jpg" alt="Slide 06" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y es posible que después de un buen esfuerzo, lleguemos a responder todas las preguntas que se nos han ocurrido, e incluso en el camino se nos ocurrieron muchas más, y las fuimos agregando. Como en este ejemplo, en el que &lt;em&gt;“total, ya que estamos…”&lt;/em&gt;, le agregamos hasta el clima y el pronóstico del tiempo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiayhdn6dwkaignqk3nwu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiayhdn6dwkaignqk3nwu.jpg" alt="Slide 07" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si bien ese dashboard puede parecer muy completo, ¿qué tan eficaz es para resolver problemas en producción? ¿Es útil para hacer troubleshooting o comprender qué está andando mal?&lt;/p&gt;

&lt;p&gt;Lo que sucede muchas veces, es que terminamos con dashboards que son como una sábana laaaarga, llena de métricas de todo tipo. Y luego, en medio de un problema en producción, nos volvemos locos tratando de comprender qué gráfico mirar y qué información nos está mostrando.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fac5lnq1bq2wohgbmd3fh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fac5lnq1bq2wohgbmd3fh.jpg" alt="Slide 08" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3hjplwz2fk0yynp16c8n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3hjplwz2fk0yynp16c8n.jpg" alt="Slide 09" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Entonces, ¿Qué preguntas de verdad importan? ¿cuáles deberíamos responder con nuestro sistema de monitoreo?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hay 2 preguntas claves que debería responder: &lt;strong&gt;qué está roto&lt;/strong&gt; y &lt;strong&gt;por qué&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estas dos preguntas deberían guiar nuestro sistema de monitoreo.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cuando intentamos responder &lt;em&gt;qué está roto&lt;/em&gt;, estamos hablando de &lt;em&gt;los síntomas&lt;/em&gt; que presenta nuestro sistema, lo cual es equivalente al &lt;em&gt;impacto&lt;/em&gt; que estamos generando sobre los usuarios (ya sean personas, u otras aplicaciones).&lt;/p&gt;

&lt;p&gt;Cuando intentamos responder &lt;em&gt;por qué se produjo ese síntoma&lt;/em&gt;, estamos hablando de la causa que lo generó.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@copyconstruct" rel="noopener noreferrer"&gt;Cindy Sridharan&lt;/a&gt;, en un post sobre &lt;a href="https://medium.com/@copyconstruct/monitoring-and-observability-8417d1952e1c" rel="noopener noreferrer"&gt;Monitoring And Observability&lt;/a&gt;, dice que nuestro sistema de monitoreo debería hacer visible o evidente cuál es el impacto que estamos generando sobre nuestros usuarios (&lt;strong&gt;what’s broken&lt;/strong&gt;), como así también comprobar que el impacto desapareció, cuando subimos un fix.&lt;/p&gt;

&lt;p&gt;Dejamos un link al &lt;a href="https://landing.google.com/sre/sre-book/chapters/monitoring-distributed-systems/" rel="noopener noreferrer"&gt;capítulo 6&lt;/a&gt; del libro de SRE de Google, de donde extrajimos este primer lineamiento, respecto al &lt;em&gt;qué&lt;/em&gt; y el &lt;em&gt;cómo&lt;/em&gt;. Y a continuación, vamos a centrarnos en cómo estas dos preguntas pueden guiar el diseño de nuestro sistema de monitoreo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxff80dz5tse7jt4azdub.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxff80dz5tse7jt4azdub.jpg" alt="Slide 10" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para comprender mejor a qué nos referimos, veamos 3 simples ejemplos de &lt;strong&gt;Síntoma&lt;/strong&gt; Vs. &lt;strong&gt;Causa&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;En el primer caso, tenemos una &lt;code&gt;API&lt;/code&gt; que responde &lt;code&gt;500s&lt;/code&gt;. El síntoma, es decir, lo que se percibe externamente, y por ende, la forma en que estamos impactando al usuario, es el hecho de estar devolviendo &lt;code&gt;500s&lt;/code&gt;. Mientras que la causa en este caso es que la Base de Datos nos rechaza las conexiones.&lt;/li&gt;
&lt;li&gt;En el segundo caso, la &lt;code&gt;API&lt;/code&gt; está respondiendo, pero de manera más lenta de lo esperado. Ese es el síntoma que se puede observar externamente. Mientras que la causa es que se están encolando requests. Es una causa intermedia, habría que analizar por qué se están encolando.&lt;/li&gt;
&lt;li&gt;En el tercer caso, el síntoma es que los usuarios no se pueden loguear, y la causa es que el cliente de autenticación, está recibiendo &lt;code&gt;503&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se llama &lt;em&gt;"monitoreo de caja negra"&lt;/em&gt; a aquellos que capturan los síntomas, ya que estamos obteniendo una visión externa del sistema. Mientras que son &lt;em&gt;"monitoreo de caja blanca"&lt;/em&gt;, aquellos que capturan eventos internos del sistema, y que generalmente permiten comprender la causa.&lt;/p&gt;

&lt;p&gt;Se dice que &lt;strong&gt;distinguir entre el qué y el comó, nos permite diseñar sistemas de monitoreo con señales más claras, y con menos ruido&lt;/strong&gt;. Esta cita es extraída del &lt;a href="https://landing.google.com/sre/sre-book/toc" rel="noopener noreferrer"&gt;libro de SRE de Google&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Un detalle que está bueno notar, es que las causas de nuestro sistema podría ser un síntoma en otro. Ese sería el caso del tercer ejemplo, donde tenemos un cliente que recibe &lt;code&gt;503&lt;/code&gt;, es decir, del otro lado hay un servicio que tiene el síntoma de no poder atender las requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo1rqsd1tlfpxmbsnf2ua.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo1rqsd1tlfpxmbsnf2ua.jpg" alt="Slide 11" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hay diferencias claves entre monitoreo de &lt;em&gt;caja negra&lt;/em&gt; y monitoreo de &lt;em&gt;caja blanca&lt;/em&gt;. Conocerlas, nos puede ayudar a armar gráficas y paneles más efectivos, que hagan foco en lo que intentan mostrar, ya sea un síntoma o una causa.&lt;/p&gt;

&lt;p&gt;En el caso de &lt;strong&gt;caja negra&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El monitoreo debe pensarse desde el punto de vista del usuario (o bien, desde el requerimiento de negocio). Por ej, preguntas como &lt;em&gt;¿Qué tan rápido esperan los usuarios que les responda mi API?&lt;/em&gt;, nos llevaría a armar un gráfico sobre tiempos de respuestas.&lt;/li&gt;
&lt;li&gt;Suelen estar controladas a través de &lt;em&gt;SLIs&lt;/em&gt; y &lt;em&gt;SLOs&lt;/em&gt; (luego veremos que son).&lt;/li&gt;
&lt;li&gt;Son relativamente fácil de conocer, dado que en general se conoce de antemano los requerimientos que el servicio intenta satisfacer.&lt;/li&gt;
&lt;li&gt;Este tipo de sistemas nos permite visualizar &lt;em&gt;problemas activos&lt;/em&gt;, es decir, que ya están ocurriendo e impactando al usuario.&lt;/li&gt;
&lt;li&gt;Esto quiere decir que &lt;strong&gt;debemos actuar de forma reactiva&lt;/strong&gt;: cuando vemos un problema, tenemos que salir corriendo a solucionarlo, porque se trata de algo que ya está impactando a los usuarios.&lt;/li&gt;
&lt;li&gt;En general, las alertas de un sistema de monitoreo de caja negra, tienden a ser las últimas en saltar.&lt;/li&gt;
&lt;li&gt;Usualmente se resuelven por las personas que están de guardia.&lt;/li&gt;
&lt;li&gt;Y generalmente están compuestos de pocas métricas, dado que el usuario típicamente no espera cosas muy complejas de nuestros servicios, simplemente quiere que funcione en tiempos adecuados, de forma adecuada, que no haya errores, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el caso de &lt;strong&gt;caja blanca&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El monitoreo debe pensarse desde un punto de vista bien técnico, basado en la arquitectura de nuestro servicio.
Generalmente se controlan a través de umbrales, dentro de los cuales podemos afirmar que nuestros componentes funcionarán bien.&lt;/li&gt;
&lt;li&gt;En general, es más difícil saber qué nos interesa monitorear, y cómo, ya que depende de conocimiento y experiencia técnica sobre los componentes del sistema.&lt;/li&gt;
&lt;li&gt;Detectan &lt;em&gt;problemas inminentes&lt;/em&gt;, es decir, que quizás aún no produjeron ninguna consecuencia, pero que de continuar así, pronto lo harán.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permiten accionar de forma proactiva&lt;/strong&gt;, dado que permiten adelantarse a los síntomas que están por ocurrir. Por ejemplo, si vemos que el espacio en disco pasó un umbral, podemos afirmar que de continuar así, pronto nos quedaremos sin disco, lo cual puede ser algo que genere algún impacto sobre el usuario, y por lo tanto podemos reaccionar de forma temprana, previniendo el problema de quedarnos sin disco.&lt;/li&gt;
&lt;li&gt;En general tiende a tener alarmas tempranas, que nos pueden prevenir incidentes.&lt;/li&gt;
&lt;li&gt;Suele haber soluciones automáticas, por ejemplo, autoscaling, rollback automático, circuit breaker, etc.&lt;/li&gt;
&lt;li&gt;Y aquí si queremos tener bastante métricas, tantas como el sistema lo necesite para demostrarnos que está bajo un estado aceptable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;De todas estas diferencias, hay una que es clave: &lt;em&gt;el enfoque con el que se enfrentan los problemas&lt;/em&gt;. Mientras que &lt;strong&gt;en uno de caja negra, el enfoque es reactivo&lt;/strong&gt; (es decir, reaccionamos cuando el usuario está siendo afectado), &lt;strong&gt;en uno de caja blanca, podemos actuar de forma proactiva&lt;/strong&gt;, antes de que el usuario se vea afectado.&lt;/p&gt;

&lt;p&gt;Ambos tipos de monitoreo son importantes y se complementan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8yx6bmddgt9zi6e9nq9s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8yx6bmddgt9zi6e9nq9s.jpg" alt="Slide 12" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6gvvm6ah3b8itmnphr4i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6gvvm6ah3b8itmnphr4i.jpg" alt="Slide 13" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A continuación, algunas buenas prácticas que fuimos incorporando.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;La simplicidad es la principal optimización de cualquier sistema&lt;/strong&gt;. El sistema de monitoreo es como cualquier otro sistema de Software, fácilmente se puede complejizar y tornar inmanejable, entre otras deficiencias. Mantener las cosas simples, ayuda a que sea fácil de comprender, de mantener y de modificar.&lt;/li&gt;
&lt;li&gt;Debe ser fácil de leer y comprender. En otras palabras, &lt;strong&gt;tiene que ser expresivo&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;No desagregar innecesariamente. Por ejemplo, si estoy midiendo tiempos, elegir apropiadamente 3 o 4 percentiles, si quiero medir errores, elegir cómo contabilizarlos, si voy a contar cantidad de errores o cantidad de success, y contar solo uno, etc.&lt;/li&gt;
&lt;li&gt;Mantener los gráficos limpios y ordenados.&lt;/li&gt;
&lt;li&gt;Las métricas y alertas que rara vez usamos, son candidatas a ser eliminadas. O bien, deberíamos pensar que cambios hay que hacerle para que pase a ser más relevante.&lt;/li&gt;
&lt;li&gt;En lo posible, tener pocas métricas, y no duplicarlas. A veces, tenemos la misma métrica tomada con distintos sistemas. Evitar la redundancia, si no, después no sabés que mirar.&lt;/li&gt;
&lt;li&gt;Poner especial atención a cómo estamos midiendo. En general, usar series de tiempo, que permitan graficar líneas continuas, es preferible a hacer checks discretos, como haríamos con &lt;code&gt;Nagios&lt;/code&gt; por ejemplo.&lt;/li&gt;
&lt;li&gt;Evitar los promedios. Esto más que nada cuando estamos midiendo tiempos. Es preferible guardar los tiempos en buckets, y visualizar la distribución, por ejemplo, percentil 50 / 75 / 90 / 99 / 99.9 / etc. También tener presente cómo están configurados los buckets, y si son acorde a los tiempos que queremos registrar.&lt;/li&gt;
&lt;li&gt;Poner un ojo en los picos, por ejemplo el percentil 99.9, o 99.99 (o más, eso depende mucho del servicio que estamos analizando). Es importante no olvidarnos de estos picos, que según la cantidad de tráfico, pueden ser significativos.&lt;/li&gt;
&lt;li&gt;Seleccionar apropiadamente la resolución, acorde a lo que estamos midiendo. La mayoría de las veces, la default que traen los herramientas, no sirve.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fihv23cscph7a35vv531c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fihv23cscph7a35vv531c.jpg" alt="Slide 14" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora vamos a mostrar 2 de las metodologías más utilizadas para monitorear.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3lk9ur1josuoxetd4ao7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3lk9ur1josuoxetd4ao7.jpg" alt="Slide 15" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.brendangregg.com/usemethod.html" rel="noopener noreferrer"&gt;USE Method&lt;/a&gt; es una metodología creada por &lt;a href="http://brendangregg.com/" rel="noopener noreferrer"&gt;Brendan Gregg&lt;/a&gt;, un especialista en análisis de Performance. Es una metodología orientada al análisis de performance, que se centra en analizar 3 aspectos de cada recurso: utilización, saturación y errores. El dice que analizando estos 3 aspectos de cada recursos, vamos a poder resolver el 80% de los casos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La utilización es qué porcentaje del tiempo está ocupado el recurso.&lt;/li&gt;
&lt;li&gt;La saturación se puede ver como una cola de tareas a despachar por el recurso. La cantidad de tareas que están encoladas, representa el grado de saturación del recurso.&lt;/li&gt;
&lt;li&gt;Errores tiene que ver con las fallas del recursos. Se puede contabilizar como un ratio del tipo &lt;code&gt;errores / total de requests&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si bien esta metodología fue creada para hacer análisis de performance, puede servir como guía para crear nuestro sistema de monitoreo de caja blanca, ya que podríamos analizar estas 3 características en cada componente / recurso que nos interese monitorear.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuxl80jdiueyxrfd9z8g7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuxl80jdiueyxrfd9z8g7.jpg" alt="Slide 16" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://landing.google.com/sre/sre-book/chapters/monitoring-distributed-systems/#xref_monitoring_golden-signals" rel="noopener noreferrer"&gt;The Four Golden Signal&lt;/a&gt; es una metodología presentada por Google en su libro de SRE. En este libro dicen que si solo pudieras medir 4 métricas de tu servicio, deberían ser la latencia, el throughput, los errores y la saturación. Esas métricas son suficiente para detectar la mayoría de los problemas.&lt;/p&gt;

&lt;p&gt;Es una metodología para desarrollar un monitoreo de caja negra.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La &lt;strong&gt;Latencia&lt;/strong&gt;, es el tiempo que tardamos en realizar algo que nos solicita el usuario. En general es el tiempo que tardamos en responder una request, o el lag en un pipeline de datos.&lt;/li&gt;
&lt;li&gt;El &lt;strong&gt;Tráfico&lt;/strong&gt;, es la cantidad de requests que estamos recibiendo. Es importante observar el tráfico, porque siempre debería cambiar de forma esperada. Si cambia de forma inesperada, puede ser síntoma de que alguien nos puso en una &lt;em&gt;blacklist&lt;/em&gt;, o bien, que no está pudiendo consumir nuestro servicio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errores&lt;/strong&gt;. Siempre es importante conocer cuántos errores tenemos y si estamos bajo una cantidad de errores aceptables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saturación&lt;/strong&gt;, ¿Qué tan estresado está nuestro servicio?. Esta métrica puede estar compuesta por diferentes aspectos de nuestro sistema. Depende mucho del tipo de servicio que estemos ofreciendo. Podría ser la cantidad de requests encoladas, o bien, si es una app &lt;code&gt;CPU Bounded&lt;/code&gt;, si la CPU está saturada podría indicarnos si el servicio está saturado o no, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5snt2vg4t3uv9f3chvt5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5snt2vg4t3uv9f3chvt5.jpg" alt="Slide 17" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este es un ejemplo de uno de nuestros servicios, monitoreado con The 4 Golden Signals. En el caso de esta aplicación, como hace un procesamiento asincrónico de los eventos que recibe, un indicador de que el servicio está saturado es la cantidad de eventos que estamos reteniendo en la cola.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa69nz40plwzlm2pfu93t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa69nz40plwzlm2pfu93t.jpg" alt="Slide 18" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para armar nuestro sistema de monitoreo, podemos tomar algunas ideas y prácticas de SRE, ya que &lt;em&gt;monitoring&lt;/em&gt; es una parte core de este rol.&lt;/p&gt;

&lt;p&gt;Por supuesto que SRE es mucho más que monitorear aplicaciones, y ni hablar si tomamos en cuenta cómo lo aplica Google. Siendo consciente de que no somos Google, ni Twitter, ni Netflix, sí creemos que es interesar tomar las cosas que nos sirven de estas prácticas, y llevarlo a nuestra realidad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frx9s4ni0ggxphhfcrr42.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frx9s4ni0ggxphhfcrr42.jpg" alt="Slide 19" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uno de los objetivos centrales de SRE es medir qué tanto se está cumpliendo con las expectativas del usuario. Para poder cuantificarlo de manera objetiva, selecciona una serie de indicadores claves, llamados &lt;a href="https://landing.google.com/sre/sre-book/chapters/service-level-objectives/#indicators-o8seIAcZ" rel="noopener noreferrer"&gt;SLI (Service Level Indicator)&lt;/a&gt;, que permitan medir si se está cumpliendo con la calidad de servicio que se pretende brindar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzxmu5lm8ftc9amu4jsd3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzxmu5lm8ftc9amu4jsd3.jpg" alt="Slide 20" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En Google, hay un &lt;em&gt;"menú de SLI"&lt;/em&gt;, que tiene una lista de &lt;em&gt;SLIs&lt;/em&gt; a aplicar en cada tipo de servicio, según la forma de interactuar que tenga el servicio con los usuarios. Por ejemplo, en un servicio donde los usuarios interactúan a través de un esquema &lt;em&gt;Request / Response&lt;/em&gt;, 3 &lt;em&gt;SLIs&lt;/em&gt; claves serían &lt;em&gt;la disponibilidad&lt;/em&gt;, &lt;em&gt;la latencia&lt;/em&gt; y &lt;em&gt;la calidad de las respuestas&lt;/em&gt;. La calidad puede ser una métrica interesante, si tenemos algún mecanismo de &lt;em&gt;graceful degradation&lt;/em&gt;. Del mismo modo, si tenemos un servicio que funciona como un &lt;em&gt;pipeline de datos&lt;/em&gt;, donde los usuarios ingresan un evento para que este sea procesado y disponibilizado, nos va a interesar observar otro tipo de indicadores, y sí podemos continuar con otros tipos de servicios.&lt;/p&gt;

&lt;p&gt;El menú sirve como una guía inicial, luego hay que analizar las necesidades particulares de cada servicio.&lt;/p&gt;

&lt;p&gt;Entonces, la forma de elegir los &lt;em&gt;SLIs&lt;/em&gt; apropiados para mi servicio sería la siguiente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;El primer paso sería elegir los &lt;em&gt;SLIs&lt;/em&gt; apropiados para el servicio que quiero monitorear.&lt;/li&gt;
&lt;li&gt;El segundo paso sería especificar qué eventos vamos a considerar &lt;em&gt;válidos&lt;/em&gt; para el &lt;em&gt;SLI&lt;/em&gt;, y qué condición deben cumplir para ser contabilizados como eventos &lt;em&gt;exitosos o buenos&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Finalmente, como tercer paso, deberíamos especificar desde donde vamos a obtener estos eventos, básicamente que tan cerca del usuario o de las apps nos vamos a situar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F32nt6aljczl4b8civiw7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F32nt6aljczl4b8civiw7.jpg" alt="Slide 21" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí un ejemplo sobre cómo podríamos agregar 2 &lt;em&gt;SLIs&lt;/em&gt; para medir &lt;em&gt;la disponibilidad&lt;/em&gt; y &lt;em&gt;la latencia&lt;/em&gt; de un servicio que expone información de los usuarios.&lt;/p&gt;

&lt;p&gt;En el caso de la &lt;em&gt;Disponibilidad&lt;/em&gt;, podemos especificar que queremos observar el porcentaje de &lt;code&gt;GETs&lt;/code&gt; que se completan con éxito, y como implementación, podemos especificar que vamos a registrar como eventos válidos todas las requests que devuelven &lt;code&gt;200s&lt;/code&gt; o &lt;code&gt;500s&lt;/code&gt; como status code, y como eventos exitosos, los que devuelven &lt;code&gt;200s&lt;/code&gt;. Entonces, podemos hacer un ratio de cantidad de &lt;code&gt;200s&lt;/code&gt; sobre cantidad de &lt;code&gt;200s + 500s&lt;/code&gt;, obteniendo &lt;em&gt;el porcentaje de &lt;code&gt;GETs&lt;/code&gt; completados con éxito&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Para la latencia, podemos especificar que nos interesa medir el porcentaje de requests que devuelven un &lt;code&gt;200s&lt;/code&gt; como status code, &lt;em&gt;en menos de 500 milisegundos&lt;/em&gt;. Como implementación, podemos especificar que los eventos válidos son todos los &lt;code&gt;200s&lt;/code&gt;, y los exitosos son los &lt;code&gt;200s&lt;/code&gt; que se resuelven en menos de 500 milisegundos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmirzhfyc4tckizl9w8tn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmirzhfyc4tckizl9w8tn.jpg" alt="Slide 22" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lo interesante es que definiendo eventos válidos y eventos exitosos para cada &lt;em&gt;SLI&lt;/em&gt;, podemos llevar todas las mediciones a porcentajes, es decir, tendríamos una unidad en común para todos los &lt;em&gt;SLIs&lt;/em&gt;. Luego, dado que son porcentajes, podemos establecer fácilmente &lt;strong&gt;objetivos&lt;/strong&gt; sobre los mismos. Estos objetivos, se los llama &lt;a href="https://landing.google.com/sre/sre-book/chapters/service-level-objectives/#objectives-g0s1tdcz" rel="noopener noreferrer"&gt;SLO (Service Level Objective)&lt;/a&gt;, y tienen que tener una ventana de tiempo sobre las que van a ser medidos. Por ejemplo, para la disponibilidad podemos establecer un &lt;em&gt;SLO&lt;/em&gt; de &lt;em&gt;99.9%&lt;/em&gt;, medido a través de todos los servidores que exponen el servicio, y en ventanas de tiempo de 24 horas. De forma análoga, podemos definir otro &lt;em&gt;SLO&lt;/em&gt; para la latencia, definiendo que queremos que por lo menos el &lt;em&gt;95%&lt;/em&gt; de las requests GET que terminan con &lt;code&gt;200s&lt;/code&gt;, se completen en menos de &lt;code&gt;500ms&lt;/code&gt;, medido a través de todos los servidores que exponen el servicio, en ventanas de tiempo de 24 horas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnn903wro4diidmc8of26.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnn903wro4diidmc8of26.jpg" alt="Slide 23" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este es un ejemplo de una de las aplicaciones que mantenemos. &lt;br&gt;
Es una app que expone un servicio para ingresar eventos y procesarlos asincrónicamente. En este servicio elegimos 3 &lt;em&gt;SLIs&lt;/em&gt;: &lt;em&gt;disponibilidad&lt;/em&gt;, &lt;em&gt;latencia&lt;/em&gt; y &lt;em&gt;el tiempo transcurrido desde que ingresa el evento, hasta que termina de procesarse&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Aún no definimos &lt;em&gt;SLOs&lt;/em&gt;, porque queremos tener un mayor historial sobre cómo usarán el servicio, pero lo que sí hicimos, es elegir algunos valores como sugerencia, y los dejamos en el título y descripción de cada panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyahy5pev8dg7qu57fk0z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyahy5pev8dg7qu57fk0z.jpg" alt="Slide 24" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Un tema muy importante en nuestro sistema de monitoreo son las alertas. Mal usadas, pueden generar más problemas que si no las tuviéramos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy3w1hzcxad2iqdqmu8un.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy3w1hzcxad2iqdqmu8un.jpg" alt="Slide 25" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Las alertas tienen que saltar solo cuando se trata de algo urgente, algo que no se puede postergar. Si la alerta está bien configurada, cuando aparece, debería querer salir corriendo. &lt;strong&gt;Tienen que estar basadas en síntomas&lt;/strong&gt;, es decir, tiene que avisarme solo si estamos generando, o estamos en camino a generar, algún impacto negativo sobre el usuario.&lt;/p&gt;

&lt;p&gt;Cuando esto no sucede, cuando las alarmas nos avisan de algo que puede esperar al otro día, o de algo que ni siquiera es un problema, entonces empiezan a surgir otros problemas que también son bastante serios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acostumbrarnos a la falsa alarma y no ver a tiempo una alarma importante.&lt;/li&gt;
&lt;li&gt;Malgastar el tiempo, ya sea por el switch mental, o por interrumpirte en un momento personal.&lt;/li&gt;
&lt;li&gt;Desmoralizar, desmotivar, generar mal predisposición a monitorear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dejamos algunas preguntas que tomamos principalmente del libro de SRE de Google, que creemos que pueden servir de guía para armar bien las alarmas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La alarma que estoy creando, va a detectar una condición que me haga reaccionar con urgencia? La situación, tiene algún accionable? Le estará impactando inmediatamente a los usuarios? Por ej, si la situación es que se cortó la red en una región, y no queda otra que esperar, no hace falta que me molesten por eso. En todo caso, cuando vuelva, si mis servicios no se pudieron recuperar solos, ahí si debería haber alguna alarma.&lt;/li&gt;
&lt;li&gt;Cuando suceda, voy a poder tomar alguna acción? Es realmente urgente o puede esperar al otro día? Por ejemplo, si en el cluster de un servicio se cayeron algunas instancias, pero el tráfico se puede seguir sirviendo con las instancias que quedaron activas, no hace falta lanzar una alerta. En todo caso notificarlo por otra vía, tal de que al día siguiente lo pueda ver.&lt;/li&gt;
&lt;li&gt;La acción podría ser automatizable? Siempre que una acción se pueda automatizar, es preferible eso. Se ahorra tiempo, es menos error prone, y no depende del conocimiento de una persona en particular.&lt;/li&gt;
&lt;li&gt;La alerta, va a molestar a otra gente innecesariamente? Ojo con el encadenamiento de alertas, debería haber una dependencia. Hay sistemas de alertas que permiten configurar eso.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¿Que hacemos con las alertas que no son urgentes? Por ej. que se caiga un nodo de un cluster. Se puede usar otro canal de comunicaciones para este tipo de notificaciones. Uno que se revise en horario laboral, y que sea parte de las tareas de mantenimiento, no de la guardia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0r6ygnfhg4qtt4413p0d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0r6ygnfhg4qtt4413p0d.jpg" alt="Slide 26" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, pero hasta acá no hablamos de logs, ni de trazas, ni de nada de todas esas herramientas que tanto se estuvieron hablando estos días. Al contrario, dijimos que el monitoreo no debe contener muchas métricas, solo las necesarias para responder &lt;strong&gt;Qué está roto&lt;/strong&gt; y &lt;strong&gt;Por Qué&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Bueno, ahora vamos a ver que para todo el resto, están las herramientas de &lt;em&gt;observability&lt;/em&gt;. Y vamos a hacer un breve repaso sobre las más importantes, dado que complementan con todo lo que nuestro sistema de monitoreo no nos alcanza a responder en momentos de &lt;strong&gt;troubleshooting&lt;/strong&gt; y &lt;strong&gt;debugging&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgqn9rl4akbaiu8086h8i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgqn9rl4akbaiu8086h8i.jpg" alt="Slide 27" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El objetivo de &lt;em&gt;Observability&lt;/em&gt; es diferente al de monitoring. El objetivo es permitirnos conocer con el mayor nivel de detalle posible, el comportamiento y estado interno de nuestro sistema. Algo que es muy importante para comprender el estado interno, es el contexto de ejecución, ya que nos permite comprender la causalidad de la serie de acciones o eventos que suceden internamente.&lt;/p&gt;

&lt;p&gt;Como se puede ver en la imagen, observability incluye las herramientas de monitoring y va más allá. Se dice que abarca todo lo que monitoring no llega a cubrir.&lt;/p&gt;

&lt;p&gt;Otro punto importante es que debe estar basado en evidencias, no en conjeturas u opiniones.&lt;/p&gt;

&lt;p&gt;Observability es un término que generó  bastante debate en estos últimos años, y se lo uso mucho de forma marketinera. Sus orígenes vienen de teoría de control, y en lo que sí podemos ponernos de acuerdo a lo largo de todo el debate que se fue dando, es que tiene que ver con conocer el estado interno y el comportamiento de un sistema.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ujqtse4i3u8bb9x1c4v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ujqtse4i3u8bb9x1c4v.jpg" alt="Slide 28" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A continuación, vamos a hacer un breve repaso sobre las herramientas de observability más usadas en un contexto de sistemas distribuidos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftg4wr8jw6i0oheqfvljo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftg4wr8jw6i0oheqfvljo.jpg" alt="Slide 29" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando intentamos resolver un problema, probablemente en algún punto queramos pasar a revisar el log.&lt;/p&gt;

&lt;p&gt;Los logs son eventos discretos que generan las aplicaciones a medida que ejecutan su propia lógica. El log que se genera para hacer observability, en general tiene datos y detalles asociados a las decisiones y caminos que que la aplicación fue tomando, tal que luego sirva para hacer diagnóstico o evidenciar lo que la aplicación hizo. Algo importante es que &lt;strong&gt;el log siempre nos habla sobre qué hizo la aplicación en el pasado&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Algunos detalles a tener en cuenta cuando agregamos logs, son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loguear con contexto. Ya sea un identificador por request, o algo que nos permita correlacionar varios logs asociados a un mismo evento.&lt;/li&gt;
&lt;li&gt;Estandarizar el log, tal de tener el mismo tipo de información en cada nivel de logueo.&lt;/li&gt;
&lt;li&gt;En lo posible, usar logs estructurado. Tal de que no esté limitado a ser leído por un humano, sino que también pueda procesarse programáticamente. Y por ejemplo, sacar métricas, agrupar, indexar fácilmente por campos específicos, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Respecto a logs estructurados, dejamos una imágen mostrada en una &lt;a href="https://www.youtube.com/watch?v=TcmvmqbrDKU" rel="noopener noreferrer"&gt;charla&lt;/a&gt; en la &lt;a href="https://grafana.com/about/events/grafanacon/2020/" rel="noopener noreferrer"&gt;GRAFANACON&lt;/a&gt; de este año, donde a partir de unas líneas de logs, se puede sacar información extra sobre la cantidad de requests, por endpoint y status code, lo cual puede ser muy útil en medio de un incidente en producción. En este caso, lo están haciendo con una query sobre &lt;strong&gt;Loki&lt;/strong&gt;, usando &lt;a href="https://github.com/grafana/loki/blob/master/docs/logql.md" rel="noopener noreferrer"&gt;LogQL&lt;/a&gt;, parecido a &lt;a href="https://prometheus.io/docs/prometheus/latest/querying/basics/" rel="noopener noreferrer"&gt;PromQL&lt;/a&gt; de &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0ohmr65jhq7so66mk3oc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0ohmr65jhq7so66mk3oc.jpg" alt="Slide 30" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí se ve un ejemplo de cómo listamos los logs de una aplicación, en este caso llamada &lt;em&gt;data-stream-in&lt;/em&gt;, usando &lt;em&gt;Loki&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5v2p0hyaivna56xsrlf4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5v2p0hyaivna56xsrlf4.jpg" alt="Slide 31" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí otro ejemplo, filtrando solo los &lt;em&gt;warnings&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftqnfwnstcb6dsnjssdv3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftqnfwnstcb6dsnjssdv3.jpg" alt="Slide 32" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y aquí otro ejemplo, armando una métrica de cantidad de logs por minuto, agrupado por nivel. En este caso vemos que tenemos logs en &lt;code&gt;INFO&lt;/code&gt; y en &lt;code&gt;WARN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkbqo9muo31d1ggsdxjks.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkbqo9muo31d1ggsdxjks.jpg" alt="Slide 33" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Otra herramienta fundamental, son las métricas. A diferencia del log, las métricas son valores agregados, tales como &lt;em&gt;contadores&lt;/em&gt;, &lt;em&gt;histogramas&lt;/em&gt;, &lt;em&gt;gauge&lt;/em&gt; (valores que pueden crecer o decrecer). Las métricas se usan tanto para conocer el estado actual de un sistema, como la tendencia o evolución que está teniendo. Esto significa que son útiles para predecir hacia donde va el sistema. Por ej, con una métrica del espacio en disco utilizado, podemos ver si estamos agotando el espacio libre y si la tendencia es quedarnos sin disco, o por el contrario, estar ganando espacio en disco.&lt;/p&gt;

&lt;p&gt;Además de las métricas del sistema en sí, como latencia, throughput, errores y saturación, es importante tener en cuenta otros aspectos subyacentes al sistema. Aspectos como los &lt;a href="https://www.azul.com/giltene-how-java-got-the-hiccups/" rel="noopener noreferrer"&gt;hiccups&lt;/a&gt; que puede tener la &lt;em&gt;VM&lt;/em&gt;, el uso de &lt;em&gt;CPU&lt;/em&gt; y cantidad de pausas introducidos por la &lt;em&gt;GC&lt;/em&gt;, son algunos de los que también hay que observar para comprender mejor la performance de nuestro sistema.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpzqzp5m00pivq4mum290.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpzqzp5m00pivq4mum290.jpg" alt="Slide 34" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí un ejemplo de métricas de sistema que tomamos en nuestras VMs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F90n5t9irsiqzzn2gap3j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F90n5t9irsiqzzn2gap3j.jpg" alt="Slide 35" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tracing es otra herramienta muy útil que permite, no solo analizar y responder preguntas sobre una aplicación en particular, sino también responder preguntas que tienen que ver con la interacción de un conjunto de aplicaciones a lo largo de un flujo que recorre una request.&lt;/p&gt;

&lt;p&gt;Una traza es un conjunto de eventos individuales que se desencadenan a través de un evento padre (en general una request). Lo interesante es que &lt;strong&gt;se puede visualizar en una sola imagen la causalidad de los eventos&lt;/strong&gt; que están relacionados con una traza en particular. Algunas preguntas interesantes que permite responder, son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cuál es el camino que recorre una request?&lt;/li&gt;
&lt;li&gt;Dónde está el cuello de botella, que ralentiza toda la ejecución?&lt;/li&gt;
&lt;li&gt;Cuanto tiempo se va en el lag de la red?&lt;/li&gt;
&lt;li&gt;Qué ocurre en cada servicio, para una request en particular?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esta &lt;em&gt;slide&lt;/em&gt; está tomada de &lt;a href="https://slides.com/diegoparra/monitoring-microservices/" rel="noopener noreferrer"&gt;una charla sobre tracing distribuido&lt;/a&gt; que dimos hace unos años, les dejamos el link a la presentación.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk1z88o88bwekfziflo1v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk1z88o88bwekfziflo1v.jpg" alt="Slide 36" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este es un ejemplo de una traza distribuida entre 2 aplicaciones. Se puede visualizar fácilmente el momento que ocupó cada aplicación, y una serie de detalles interesantes en cada &lt;em&gt;span&lt;/em&gt;, como &lt;em&gt;headers&lt;/em&gt;, &lt;em&gt;tiempos&lt;/em&gt;, &lt;em&gt;status code&lt;/em&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvhogt0b6aw7eszhguos3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvhogt0b6aw7eszhguos3.jpg" alt="Slide 37" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;En resumen:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usemos &lt;a href="https://landing.google.com/sre/sre-book/chapters/monitoring-distributed-systems/#xref_monitoring_golden-signals" rel="noopener noreferrer"&gt;The Four Golden Signal&lt;/a&gt; y &lt;a href="http://www.brendangregg.com/usemethod.html" rel="noopener noreferrer"&gt;USE Method&lt;/a&gt; para monitorear nuestros servicios.&lt;/li&gt;
&lt;li&gt;Instrumentemos nuestros servicios tan pronto como sea posible.&lt;/li&gt;
&lt;li&gt;Combinemos &lt;em&gt;profiling&lt;/em&gt;, &lt;em&gt;logs&lt;/em&gt; y &lt;em&gt;trazas&lt;/em&gt;, como herramientas auxiliares para hacer &lt;em&gt;troubleshooting&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterar&lt;/strong&gt;. Esto es un proceso iterativo. Empecemos de a poco, como dijimos, manteniendo la simpleza, y evolucionemos iterativamente nuestro sistema de monitoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Después de desarrollar todos estos temas algunas de las preguntas abiertas, y otras no tanto, que se nos ocurren son:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0kldvns9ejhz8gn9dzpy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0kldvns9ejhz8gn9dzpy.jpg" alt="Slide 42" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Algunas de las preguntas anteriores nos lleva a una línea de pensamiento donde la &lt;em&gt;controlabilidad es el fin de la observabilidad&lt;/em&gt;, y en un sistema que se autocontrola a partir de su dinamismo y donde no está solo en el universo sino que se comunica enviando y recibiendo señales que influencian a otros, y que con el tiempo ayudan a inferir el estado de los demás y el de uno mismo.&lt;/p&gt;

&lt;p&gt;Si seguimos la idea de la &lt;em&gt;controlabilidad&lt;/em&gt; caemos en la &lt;em&gt;Teoría del Control&lt;/em&gt; que hace 2000 años atrás fue usada por los egipcios en un reloj de agua (&lt;em&gt;Clepsidra&lt;/em&gt;), o un poco más acá cerca, en la segunda guerra mundial se desarrollaban armas que se apoyaban en esta idea como por ejemplo los cañones antiaéreos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjzmso4gnvyarq8gy3gea.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjzmso4gnvyarq8gy3gea.jpg" alt="Slide 46" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se usa de manera intensiva en:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control de Procesos.&lt;/li&gt;
&lt;li&gt;Electrónica.&lt;/li&gt;
&lt;li&gt;Industria Aeroespacial.&lt;/li&gt;
&lt;li&gt;Automatización de manufactura.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgffkcmafd6j0va6oflts.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgffkcmafd6j0va6oflts.jpg" alt="Slide 47" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El principio básico es comparar de manera continua la salida actual del sistema con el valor de referencia, y aplicar cambios a la entrada del sistema para contrarrestar cualquier desviación que exista entre la salida y el valor de referencia.&lt;/p&gt;

&lt;p&gt;Si pensamos en código, dentro de un &lt;code&gt;while(true)&lt;/code&gt; tenemos el estado actual y el deseado, e intentamos en todo momento que se llegue al valor deseado aplicando correcciones con el feedback loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while(true) {
    currentState = getCurrentState()
    desiredState = getDesiredState()
    makeConform(currentState, desiredState)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Algunos ejemplos conocidos donde se utiliza son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control de velocidad de un auto.&lt;/li&gt;
&lt;li&gt;Cooler del CPU donde la métrica que trackeamos es la temperatura y lo que ajustamos es el voltaje aplicado al cooler.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Kubernetes&lt;/code&gt; y el autoscaling utiliza un &lt;code&gt;PID&lt;/code&gt; (Proportional, Integral, Derivative) Loop con algunos checks y algún que otro artilugio.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Control plane&lt;/code&gt; de &lt;em&gt;Amazon&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flpkr0nsqhixekh4ib4es.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flpkr0nsqhixekh4ib4es.jpg" alt="Slide 44" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gracias!!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>observability</category>
      <category>sre</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
