<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://seomis.cc/feed.xml" rel="self" type="application/atom+xml" /><link href="https://seomis.cc/" rel="alternate" type="text/html" /><updated>2025-06-25T14:31:54+00:00</updated><id>https://seomis.cc/feed.xml</id><title type="html">seomis.github.io</title><entry><title type="html">Reading a `pt-query-digest` Report Without Losing Your Mind</title><link href="https://seomis.cc/blog/slow-query-log-interpretation" rel="alternate" type="text/html" title="Reading a `pt-query-digest` Report Without Losing Your Mind" /><published>2025-05-02T00:00:00+00:00</published><updated>2025-05-02T00:00:00+00:00</updated><id>https://seomis.cc/blog/slow-query-log-interpretation</id><content type="html" xml:base="https://seomis.cc/blog/slow-query-log-interpretation"><![CDATA[<p>You’ve run <code class="language-plaintext highlighter-rouge">pt-query-digest</code> on your MySQL slow log. Now you’re staring at a huge wall of text and wondering what to do with it. Here’s a practical breakdown of how to actually make sense of it — and fix slow queries that are dragging your database down.</p>

<hr />

<h2 id="1-start-with-the-summary">1. Start with the Summary</h2>

<p>Right at the top, you’ll see something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 1620 total queries
# 161 unique query patterns
# Time range: April 17–30, 2025
# Exec time avg: 22s
# Rows examined avg: 5.34M
</code></pre></div></div>
<p><strong>What this tells you:</strong></p>
<ul>
  <li>💀 22 seconds average execution time is alarmingly high.</li>
  <li>🧐 5.34 million rows examined per query suggests indexing problems.</li>
</ul>

<p>This section gives you a high-level health check of your workload. If it looks bad, it probably is.</p>

<hr />

<h2 id="2-check-the-profile-section">2. Check the “Profile” Section</h2>

<p>The profile ranks queries by their total response time contribution.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Rank Query ID                            Response time   Calls R/Call   V
# ==== =================================== =============== ===== ======== =
#    1 0x3A250BE32D8B29F0                  12340.7 33.8%    381  32.3906  0.42
#    2 0x4B3D9E81C5C0BC7B                   4313.9 11.8%     11 392.1736  0.01
</code></pre></div></div>
<p><strong>How to read this:</strong></p>
<ul>
  <li>🔢 Rank: Based on total response time.</li>
  <li>🧠 Query ID: A fingerprint of the query (use it to search further down).</li>
  <li>⏱ Response Time: How long this query took in total (and % of the total).</li>
  <li>🔁 Calls: How many times this query ran.</li>
  <li>⚠️ R/Call: Average time per execution — high values here are red flags.</li>
</ul>

<hr />

<h2 id="3-analyze-each-query-section">3. Analyze Each Query Section</h2>

<p>Scroll down for details on each top query. You’ll see blocks like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Query 1: 381 QPS, 12.34ks total, 33.8% of all time...
# Rank: 1
# Time range: 2025-04-17 to 2025-04-30
#
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count          23     381
# Exec time      33 12341s      1s    160s     32s     70s     24s     28s
</code></pre></div></div>
<p>Look for:</p>
<ul>
  <li>Execution time patterns — are they spiky?</li>
  <li>High max or 95th percentile values? That’s trouble.</li>
  <li>Rows examined vs rows sent — are we reading too much and returning too little?</li>
</ul>

<p>Then you’ll find:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Tables
SHOW TABLE STATUS FROM `database` LIKE 'users'\G
SHOW CREATE TABLE `database`.`users`\G
EXPLAIN SELECT * FROM users WHERE last_login &lt; '2025-01-01' AND status = 'inactive'\G
</code></pre></div></div>

<p>Check:</p>
<ul>
  <li>Are there missing indexes?</li>
  <li>Are we scanning the whole table (<code class="language-plaintext highlighter-rouge">type: ALL</code>)?</li>
  <li>Is MySQL using a key (<code class="language-plaintext highlighter-rouge">key: NULL</code> means no index was used)?</li>
</ul>

<hr />

<h2 id="4-know-the-red-flags-">4. Know the Red Flags 🚩</h2>

<p>Watch out for:</p>

<ul>
  <li>⏳ High average time per call with low execution count → likely reporting/batch jobs.</li>
  <li>🔁 High call counts with moderate execution time → small optimizations can have huge payoff.</li>
  <li>📊 Rows examined » Rows sent → indexing issues.</li>
  <li>🔐 High lock time → contention problems.</li>
  <li>❗ EXPLAIN mentions:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">Using filesort</code></li>
      <li><code class="language-plaintext highlighter-rouge">Using temporary</code></li>
      <li><code class="language-plaintext highlighter-rouge">type: ALL</code></li>
      <li><code class="language-plaintext highlighter-rouge">key: NULL</code></li>
    </ul>
  </li>
  <li>🧮 Functions on indexed columns: <code class="language-plaintext highlighter-rouge">DATE(created_at)</code>, <code class="language-plaintext highlighter-rouge">MONTH(...)</code>, etc.</li>
</ul>

<hr />

<h2 id="5-prioritize-wisely">5. Prioritize Wisely</h2>

<p>Focus on the queries that:</p>

<ul>
  <li>Take up &gt;10% of total time</li>
  <li>Are called hundreds or thousands of times</li>
  <li>Examine huge numbers of rows unnecessarily</li>
  <li>Lock up tables or create contention</li>
</ul>

<hr />

<h2 id="6-fix-them-">6. Fix Them 🛠</h2>

<p>Once you’ve picked your top offenders:</p>

<ul>
  <li>✅ Add or adjust indexes (on WHERE, JOIN, GROUP BY columns)</li>
  <li>🔄 Rewrite queries for better execution plans</li>
  <li>💡 Avoid functions in WHERE clauses that disable indexes</li>
  <li>🧊 Cache results when appropriate</li>
  <li>🔍 Use <code class="language-plaintext highlighter-rouge">EXPLAIN</code> to check what MySQL is doing behind the scenes</li>
</ul>

<hr />

<h2 id="bonus-use-grep-to-automate-the-hunt">Bonus: Use Grep to Automate the Hunt</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Profile section</span>
<span class="nb">grep</span> <span class="nt">-A</span> 10 <span class="s2">"# Profile"</span> slow-queries.txt

<span class="c"># High row scan, low return</span>
<span class="nb">grep</span> <span class="nt">-A</span> 20 <span class="s2">"Rows examine.*M"</span> slow-queries.txt

<span class="c"># Filesorts or temp tables</span>
<span class="nb">grep</span> <span class="nt">-A</span> 10 <span class="s2">"Using temporary"</span> slow-queries.txt
<span class="nb">grep</span> <span class="nt">-A</span> 10 <span class="s2">"Using filesort"</span> slow-queries.txt

<span class="c"># Full table scans</span>
<span class="nb">grep</span> <span class="nt">-A</span> 10 <span class="s2">"type: ALL"</span> slow-queries.txt
<span class="nb">grep</span> <span class="nt">-A</span> 10 <span class="s2">"key: NULL"</span> slow-queries.txt

<span class="c"># Lock time issues</span>
<span class="nb">grep</span> <span class="nt">-A</span> 5 <span class="s2">"Lock time.*[0-9]s"</span> slow-queries.txt
</code></pre></div></div>

<hr />

<h2 id="tldr-">TL;DR 🧠</h2>

<ul>
  <li>🔍 Start with the Profile section</li>
  <li>🚨 Look for high response time or bad EXPLAIN signs</li>
  <li>⚙️ Focus on top 5–10 offenders</li>
  <li>🔧 Fix indexes, rewrite bad queries, reduce rows examined</li>
  <li>Slow queries are normal. Staying blind to them isn’t. Learn the patterns, spot the pain points, and chip away at them. Your database — and your users — will notice.
    <blockquote>
      <p><strong>Note:</strong> While tools like <code class="language-plaintext highlighter-rouge">pt-query-digest</code> provide powerful insights, nothing replaces understanding the <strong>context</strong> in which these queries run. Sometimes, there are valid tradeoffs that justify a “slow” query, or cases where taking action could cause more disruption than leaving things as they are—<em>at least for the time being</em>. Use the data to inform your decisions, <strong>but don’t skip the thinking part</strong>.</p>
    </blockquote>
  </li>
</ul>

<hr />
<h2 id="further-reading">Further Reading</h2>

<p>If you’re interested in diving deeper into query optimization, MySQL performance, and related topics, check out the following resources:</p>

<p><strong><a href="https://www.percona.com/blog/">MySQL Performance Blog</a></strong><br />
  Percona’s official blog provides deep dives into MySQL performance tuning, optimization tips, and case studies.</p>

<p><strong><a href="https://www.percona.com/doc/percona-toolkit/pt-query-digest.html">pt-query-digest Manual</a></strong><br />
  Official documentation for <code class="language-plaintext highlighter-rouge">pt-query-digest</code> which explains its features and how to interpret its reports.</p>

<p><strong><a href="https://www.percona.com/software/pmm">Percona Monitoring and Management (PMM)</a></strong>
  An open source database monitoring, observability, and management tool.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[🐢 A quick guide to decoding pt-query-digest reports and fixing slow MySQL queries.]]></summary></entry><entry><title type="html">Understanding gRPC Keepalive, ENHANCE_YOUR_CALM, and Connection Health</title><link href="https://seomis.cc/blog/grpc-enhance-your-calm" rel="alternate" type="text/html" title="Understanding gRPC Keepalive, ENHANCE_YOUR_CALM, and Connection Health" /><published>2025-04-23T00:00:00+00:00</published><updated>2025-04-23T00:00:00+00:00</updated><id>https://seomis.cc/blog/grpc-enhance-your-calm</id><content type="html" xml:base="https://seomis.cc/blog/grpc-enhance-your-calm"><![CDATA[<p>In distributed systems, maintaining stable connections between services is critical. gRPC, built directly on HTTP/2, provides sophisticated connection management mechanisms that need proper configuration. We will explore gRPC connection health management, keepalive mechanisms, and troubleshooting techniques for robust microservice communication.</p>

<h2 id="grpc-and-http2-the-foundation">gRPC and HTTP/2: The Foundation</h2>

<p>gRPC is explicitly built on HTTP/2, leveraging its advanced features to enable efficient RPC communication:</p>

<ul>
  <li><strong>Multiplexing</strong>: Multiple RPCs share a single connection</li>
  <li><strong>Header compression</strong>: Reduces overhead for metadata</li>
  <li><strong>Binary protocol</strong>: More efficient encoding than text-based protocols</li>
  <li><strong>Bidirectional streaming</strong>: Enables complex communication patterns</li>
  <li><strong>Flow control</strong>: Prevents overwhelming receivers with too much data</li>
</ul>

<p>Each gRPC call maps directly to an HTTP/2 stream, with request/response messages transmitted as HTTP/2 DATA frames. This tight integration with HTTP/2 is fundamental to gRPC’s design and capabilities.</p>

<h2 id="keepalive-pings-the-foundation-of-connection-health">Keepalive Pings: The Foundation of Connection Health</h2>

<p>Keepalive pings serve as the heartbeat of gRPC connections, performing several critical functions:</p>

<ul>
  <li><strong>Dead connection detection</strong>: Identify network failures without waiting for real RPC failures</li>
  <li><strong>NAT and firewall traversal</strong>: Prevent connection closure by intermediate network devices</li>
  <li><strong>Load balancer session maintenance</strong>: Keep connections alive through load balancers with timeout policies</li>
</ul>

<h3 id="client-keepalive-configuration">Client Keepalive Configuration</h3>

<p>In gRPC, the <code class="language-plaintext highlighter-rouge">keepalive.ClientParameters</code> structure offers fine-grained control:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">keepalive</span><span class="o">.</span><span class="n">ClientParameters</span><span class="p">{</span>
    <span class="n">Time</span><span class="o">:</span>                <span class="o">&lt;</span><span class="n">duration</span><span class="o">&gt;</span><span class="p">,</span>    <span class="c">// How often to send pings</span>
    <span class="n">Timeout</span><span class="o">:</span>             <span class="o">&lt;</span><span class="n">duration</span><span class="o">&gt;</span><span class="p">,</span>    <span class="c">// How long to wait for a response</span>
    <span class="n">PermitWithoutStream</span><span class="o">:</span> <span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span>         <span class="c">// Allow pings on idle connections</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To ensure the reliability of long-lived connections experiencing sporadic traffic patterns, the <code class="language-plaintext highlighter-rouge">PermitWithoutStream</code> parameter is crucial. Setting it to true allows clients to proactively initiate health checks even during idle periods, directly contributing to robust connection management.</p>
<h2 id="server-enforcement-policy-protection-against-abuse">Server Enforcement Policy: Protection Against Abuse</h2>

<p>Servers protect themselves using the <code class="language-plaintext highlighter-rouge">EnforcementPolicy</code>, which contains critical parameters:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">keepalive</span><span class="o">.</span><span class="n">EnforcementPolicy</span><span class="p">{</span>
    <span class="n">MinTime</span><span class="o">:</span>             <span class="o">&lt;</span><span class="n">duration</span><span class="o">&gt;</span><span class="p">,</span>    <span class="c">// Minimum time between client pings</span>
    <span class="n">PermitWithoutStream</span><span class="o">:</span> <span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span>         <span class="c">// Whether to allow pings without active streams</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="the-default-5-minute-rule">The Default 5-Minute Rule</h3>

<p>Most gRPC servers set <code class="language-plaintext highlighter-rouge">MinTime</code> to <strong>5 minutes</strong> (300 seconds) by default. This means:</p>

<ul>
  <li>Clients must not ping more frequently than once every 5 minutes</li>
  <li>This applies regardless of whether streams are active</li>
</ul>

<p>When clients violate this policy, the server responds with the infamous <code class="language-plaintext highlighter-rouge">ENHANCE_YOUR_CALM</code> error.</p>

<h2 id="anatomy-of-an-enhance_your_calm-error">Anatomy of an ENHANCE_YOUR_CALM Error</h2>

<p>The <code class="language-plaintext highlighter-rouge">ENHANCE_YOUR_CALM</code> error (HTTP/2 error code 0xB) is more than just a clever reference to Demolition Man. It’s a critical signal that your client is overwhelming the server with pings.</p>

<h3 id="the-error-sequence-and-connection-lifecycle">The Error Sequence and Connection Lifecycle</h3>

<p>When a server detects ping policy violations:</p>

<ol>
  <li>It constructs a <code class="language-plaintext highlighter-rouge">GOAWAY</code> frame with:
    <ul>
      <li>Error code: <code class="language-plaintext highlighter-rouge">ENHANCE_YOUR_CALM</code> (0xB)</li>
      <li>Debug data: <code class="language-plaintext highlighter-rouge">"too_many_pings"</code> (ASCII string)</li>
    </ul>
  </li>
  <li>Sends this frame to the client</li>
  <li>May begin connection shutdown procedures, but doesn’t necessarily close the connection immediately</li>
</ol>

<h3 id="client-side-effects-and-connection-state">Client-Side Effects and Connection State</h3>

<p>The client response to ENHANCE_YOUR_CALM is more nuanced than immediate termination:</p>

<ol>
  <li>The client connection manager marks the connection as unhealthy</li>
  <li>New RPCs are typically redirected to other connections or trigger reconnection attempts</li>
  <li>In-flight RPCs may complete if the server allows them to finish</li>
  <li>The connection eventually transitions to closed state after in-flight RPCs complete or time out</li>
</ol>

<p>A typical error sequence in logs:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[transport] Client received GoAway with error code ENHANCE_YOUR_CALM and debug data equal to ASCII "too_many_pings"
// Some time later, after in-flight RPCs complete or time out:
[transport] Connection closed with error: connection error: code = Unavailable desc = transport is closing
</code></pre></div></div>

<p>The connection closure is not immediate but a gradual process controlled by both client and server behavior.</p>

<h2 id="proper-configuration-finding-the-balance">Proper Configuration: Finding the Balance</h2>

<p>The key to avoiding <code class="language-plaintext highlighter-rouge">ENHANCE_YOUR_CALM</code> is respecting the server’s <code class="language-plaintext highlighter-rouge">MinTime</code> policy while ensuring connections remain healthy.</p>

<h3 id="safe-client-configuration">Safe Client Configuration</h3>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">grpc</span><span class="o">.</span><span class="n">WithKeepaliveParams</span><span class="p">(</span><span class="n">keepalive</span><span class="o">.</span><span class="n">ClientParameters</span><span class="p">{</span>
    <span class="n">Time</span><span class="o">:</span>                <span class="m">5</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Minute</span><span class="p">,</span>     <span class="c">// Match server's MinTime (usually 5m)</span>
    <span class="n">Timeout</span><span class="o">:</span>             <span class="m">20</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>    <span class="c">// Reasonable timeout for ping response</span>
    <span class="n">PermitWithoutStream</span><span class="o">:</span> <span class="no">true</span><span class="p">,</span>                <span class="c">// Allow pings on idle connections</span>
<span class="p">})</span>
</code></pre></div></div>

<h3 id="for-high-availability-requirements">For High-Availability Requirements</h3>

<p>When you need more aggressive health checking but must respect server policies:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Client configuration</span>
<span class="n">grpc</span><span class="o">.</span><span class="n">WithKeepaliveParams</span><span class="p">(</span><span class="n">keepalive</span><span class="o">.</span><span class="n">ClientParameters</span><span class="p">{</span>
    <span class="n">Time</span><span class="o">:</span>                <span class="m">5</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Minute</span><span class="p">,</span>     <span class="c">// Respect server's MinTime</span>
    <span class="n">Timeout</span><span class="o">:</span>             <span class="m">10</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>    <span class="c">// Faster failure detection</span>
    <span class="n">PermitWithoutStream</span><span class="o">:</span> <span class="no">true</span><span class="p">,</span>                <span class="c">// Check idle connections too</span>
<span class="p">})</span>

<span class="c">// If you control the server:</span>
<span class="n">keepalive</span><span class="o">.</span><span class="n">EnforcementPolicy</span><span class="p">{</span>
    <span class="n">MinTime</span><span class="o">:</span>             <span class="m">2</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Minute</span><span class="p">,</span>     <span class="c">// Allow more frequent pings (but be careful!)</span>
    <span class="n">PermitWithoutStream</span><span class="o">:</span> <span class="no">true</span><span class="p">,</span>                <span class="c">// Allow pings on idle connections</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="environment-specific-considerations">Environment-Specific Considerations</h3>

<p>In Kubernetes or containerized environments, consider:</p>

<ul>
  <li>Network policies that might drop idle connections</li>
  <li>Service mesh proxies with their own timeout configurations</li>
  <li>Load balancer idle connection limits</li>
</ul>

<p>You may need to adjust settings based on your specific infrastructure.</p>

<h2 id="advanced-connection-health-monitoring">Advanced Connection Health Monitoring</h2>

<p>Beyond simple keepalives, implement comprehensive connection health monitoring.</p>

<h3 id="connection-state-transitions">Connection State Transitions</h3>

<p>gRPC connections move through these states:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">IDLE</code>: No active RPCs, connection established but unused</li>
  <li><code class="language-plaintext highlighter-rouge">CONNECTING</code>: Attempting to establish connection</li>
  <li><code class="language-plaintext highlighter-rouge">READY</code>: Connection established and healthy</li>
  <li><code class="language-plaintext highlighter-rouge">TRANSIENT_FAILURE</code>: Temporary failure, will retry</li>
  <li><code class="language-plaintext highlighter-rouge">SHUTDOWN</code>: Connection is closing</li>
</ul>

<h3 id="implementing-a-robust-health-check">Implementing a Robust Health Check</h3>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">monitorConnectionHealth</span><span class="p">(</span><span class="n">ctx</span> <span class="n">context</span><span class="o">.</span><span class="n">Context</span><span class="p">,</span> <span class="n">conn</span> <span class="o">*</span><span class="n">grpc</span><span class="o">.</span><span class="n">ClientConn</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">ticker</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">NewTicker</span><span class="p">(</span><span class="m">30</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span>
    <span class="k">defer</span> <span class="n">ticker</span><span class="o">.</span><span class="n">Stop</span><span class="p">()</span>
    
    <span class="k">for</span> <span class="p">{</span>
        <span class="k">select</span> <span class="p">{</span>
        <span class="k">case</span> <span class="o">&lt;-</span><span class="n">ctx</span><span class="o">.</span><span class="n">Done</span><span class="p">()</span><span class="o">:</span>
            <span class="k">return</span>
        <span class="k">case</span> <span class="o">&lt;-</span><span class="n">ticker</span><span class="o">.</span><span class="n">C</span><span class="o">:</span>
            <span class="n">state</span> <span class="o">:=</span> <span class="n">conn</span><span class="o">.</span><span class="n">GetState</span><span class="p">()</span>
            
            <span class="k">switch</span> <span class="n">state</span> <span class="p">{</span>
            <span class="k">case</span> <span class="n">connectivity</span><span class="o">.</span><span class="n">Ready</span><span class="o">:</span>
                <span class="c">// Connection healthy, nothing to do</span>
                <span class="n">log</span><span class="o">.</span><span class="n">Debug</span><span class="p">(</span><span class="s">"gRPC connection healthy"</span><span class="p">)</span>
            <span class="k">case</span> <span class="n">connectivity</span><span class="o">.</span><span class="n">Idle</span><span class="o">:</span>
                <span class="c">// Proactively wake up the connection</span>
                <span class="n">log</span><span class="o">.</span><span class="n">Debug</span><span class="p">(</span><span class="s">"gRPC connection idle, reconnecting"</span><span class="p">)</span>
                <span class="n">conn</span><span class="o">.</span><span class="n">Connect</span><span class="p">()</span>
            <span class="k">case</span> <span class="n">connectivity</span><span class="o">.</span><span class="n">TransientFailure</span><span class="o">:</span>
                <span class="n">log</span><span class="o">.</span><span class="n">Warn</span><span class="p">(</span><span class="s">"gRPC connection in transient failure state"</span><span class="p">)</span>
                <span class="c">// Consider notifying monitoring systems</span>
            <span class="k">case</span> <span class="n">connectivity</span><span class="o">.</span><span class="n">Shutdown</span><span class="o">:</span>
                <span class="n">log</span><span class="o">.</span><span class="n">Error</span><span class="p">(</span><span class="s">"gRPC connection shutdown"</span><span class="p">)</span>
                <span class="c">// Handle graceful shutdown or reconnection logic</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="proactive-health-checks">Proactive Health Checks</h3>

<p>For critical applications requiring robust connection management, proactively verifying the health of connections is paramount. While a custom echo service, like the example HealthCheck.Echo, could be implemented for explicit health verification, gRPC offers a more standardized and widely supported solution out of the box: the Health Checking Protocol. This default protocol provides mechanisms for clients to query the health status of gRPC servers and specific services, ensuring early detection of potential issues and contributing to more reliable and resilient applications. Leveraging gRPC’s built-in health checks is generally recommended for its interoperability and comprehensive features.</p>

<h2 id="handling-pod-rotation-in-kubernetes-environments">Handling Pod Rotation in Kubernetes Environments</h2>

<p>In containerized environments, gRPC servers running in pods will regularly rotate during deployments, scaling events, or node failures. Clients must be designed to handle this gracefully.</p>

<h3 id="dns-based-service-discovery">DNS-Based Service Discovery</h3>

<p>Clients should connect to Kubernetes Services rather than directly to pods:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">conn</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">grpc</span><span class="o">.</span><span class="n">Dial</span><span class="p">(</span>
    <span class="s">"my-service.namespace.svc.cluster.local:5000"</span><span class="p">,</span> 
    <span class="n">grpc</span><span class="o">.</span><span class="n">WithDefaultServiceConfig</span><span class="p">(</span><span class="s">`{"loadBalancingPolicy":"round_robin"}`</span><span class="p">),</span>
    <span class="c">// other options...</span>
<span class="p">)</span>
</code></pre></div></div>

<p>This approach lets Kubernetes handle endpoint updates transparently when pods change.</p>

<h3 id="connection-draining-during-pod-rotation">Connection Draining During Pod Rotation</h3>

<p>When a pod terminates in Kubernetes:</p>

<ol>
  <li>The pod receives a SIGTERM signal</li>
  <li>It’s removed from the Service endpoints list</li>
  <li>A grace period (default 30s) allows for connection draining</li>
</ol>

<p>Properly implemented gRPC servers handle this with graceful shutdown:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
    <span class="o">&lt;-</span><span class="n">ctx</span><span class="o">.</span><span class="n">Done</span><span class="p">()</span> <span class="c">// Context canceled on SIGTERM</span>
    <span class="n">grpcServer</span><span class="o">.</span><span class="n">GracefulStop</span><span class="p">()</span> <span class="c">// Stops accepting new requests, waits for existing ones</span>
<span class="p">}()</span>
</code></pre></div></div>

<h3 id="client-side-load-balancing-for-pod-changes">Client-Side Load Balancing for Pod Changes</h3>

<p>To handle pod rotations, configure client-side load balancing:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">conn</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">grpc</span><span class="o">.</span><span class="n">Dial</span><span class="p">(</span>
    <span class="n">target</span><span class="p">,</span>
    <span class="n">grpc</span><span class="o">.</span><span class="n">WithDefaultServiceConfig</span><span class="p">(</span><span class="s">`{
        "loadBalancingPolicy": "round_robin",
        "methodConfig": [{
            "name": [{"service": ""}],
            "retryPolicy": {
                "MaxAttempts": 5,
                "InitialBackoff": "0.1s",
                "MaxBackoff": "10s",
                "BackoffMultiplier": 2.0,
                "RetryableStatusCodes": ["UNAVAILABLE"]
            }
        }]
    }`</span><span class="p">),</span>
<span class="p">)</span>
</code></pre></div></div>

<p>When a pod rotates out:</p>
<ol>
  <li>Connections to that pod eventually fail</li>
  <li>The load balancer marks that subchannel as unhealthy</li>
  <li>Requests are routed to remaining healthy pods</li>
  <li>Client discovers new pods through DNS resolution</li>
</ol>

<h3 id="best-practices-for-pod-rotation-resilience">Best Practices for Pod Rotation Resilience</h3>

<ol>
  <li><strong>Use connection pools to multiple endpoints</strong> - Don’t rely on a single connection</li>
  <li><strong>Configure appropriate request timeouts</strong> - Prevent requests from hanging during pod termination:
    <div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ctx</span><span class="p">,</span> <span class="n">cancel</span> <span class="o">:=</span> <span class="n">context</span><span class="o">.</span><span class="n">WithTimeout</span><span class="p">(</span><span class="n">context</span><span class="o">.</span><span class="n">Background</span><span class="p">(),</span> <span class="m">3</span><span class="o">*</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span>
<span class="k">defer</span> <span class="n">cancel</span><span class="p">()</span>
<span class="n">response</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">MyMethod</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">request</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Implement circuit breakers</strong> - Protect against cascading failures during mass rotations</li>
  <li><strong>Configure proper Kubernetes readiness probes</strong> - Ensure traffic only routes to fully initialized pods:
    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">readinessProbe</span><span class="pi">:</span>
  <span class="na">exec</span><span class="pi">:</span>
    <span class="na">command</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">/bin/grpc_health_probe"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">-addr=:50051"</span><span class="pi">]</span>
  <span class="na">initialDelaySeconds</span><span class="pi">:</span> <span class="m">5</span>
  <span class="na">periodSeconds</span><span class="pi">:</span> <span class="m">10</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Buffer requests during reconnection periods</strong> - For non-critical traffic, consider queuing requests that can be retried later</li>
</ol>

<h2 id="handling-reconnection-logic">Handling Reconnection Logic</h2>

<p>When connections fail, proper reconnection logic is essential:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">createClientWithReconnection</span><span class="p">()</span> <span class="o">*</span><span class="n">grpc</span><span class="o">.</span><span class="n">ClientConn</span> <span class="p">{</span>
    <span class="c">// Exponential backoff configuration</span>
    <span class="n">backoffConfig</span> <span class="o">:=</span> <span class="n">backoff</span><span class="o">.</span><span class="n">Config</span><span class="p">{</span>
        <span class="n">BaseDelay</span><span class="o">:</span>  <span class="m">1.0</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
        <span class="n">Multiplier</span><span class="o">:</span> <span class="m">1.6</span><span class="p">,</span>
        <span class="n">Jitter</span><span class="o">:</span>     <span class="m">0.2</span><span class="p">,</span>
        <span class="n">MaxDelay</span><span class="o">:</span>   <span class="m">120</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
    <span class="p">}</span>
    
    <span class="n">conn</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">grpc</span><span class="o">.</span><span class="n">Dial</span><span class="p">(</span>
        <span class="n">serverAddress</span><span class="p">,</span>
        <span class="n">grpc</span><span class="o">.</span><span class="n">WithKeepaliveParams</span><span class="p">(</span><span class="n">keepalive</span><span class="o">.</span><span class="n">ClientParameters</span><span class="p">{</span>
            <span class="n">Time</span><span class="o">:</span>                <span class="m">5</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Minute</span><span class="p">,</span>
            <span class="n">Timeout</span><span class="o">:</span>             <span class="m">20</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
            <span class="n">PermitWithoutStream</span><span class="o">:</span> <span class="no">true</span><span class="p">,</span>
        <span class="p">}),</span>
        <span class="n">grpc</span><span class="o">.</span><span class="n">WithConnectParams</span><span class="p">(</span><span class="n">grpc</span><span class="o">.</span><span class="n">ConnectParams</span><span class="p">{</span>
            <span class="n">Backoff</span><span class="o">:</span>           <span class="n">backoffConfig</span><span class="p">,</span>
            <span class="n">MinConnectTimeout</span><span class="o">:</span> <span class="m">20</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span>
        <span class="p">}),</span>
        <span class="n">grpc</span><span class="o">.</span><span class="n">WithDefaultServiceConfig</span><span class="p">(</span><span class="s">`{
            "methodConfig": [{
                "name": [{"service": ""}],
                "retryPolicy": {
                    "MaxAttempts": 5,
                    "InitialBackoff": "0.1s",
                    "MaxBackoff": "10s",
                    "BackoffMultiplier": 2.0,
                    "RetryableStatusCodes": ["UNAVAILABLE"]
                }
            }]
        }`</span><span class="p">),</span>
    <span class="p">)</span>
    
    <span class="k">return</span> <span class="n">conn</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="testing-connection-resilience">Testing Connection Resilience</h2>

<p>Implement tests that verify your application handles connection issues gracefully:</p>

<ol>
  <li><strong>Chaos testing</strong>: Use tools like Toxiproxy to simulate network partitions</li>
  <li><strong>Load balancer draining</strong>: Test behavior when servers are removed from rotation</li>
  <li><strong>Server restarts</strong>: Ensure clients reconnect properly after server restarts</li>
  <li><strong>Policy violation testing</strong>: Deliberately configure incorrect keepalive settings to verify proper error handling</li>
  <li><strong>Pod rotation simulation</strong>: Test resilience during Kubernetes deployments</li>
</ol>

<h2 id="best-practices-and-common-pitfalls">Best Practices and Common Pitfalls</h2>

<h3 id="dos">Do’s</h3>
<ul>
  <li>Match client <code class="language-plaintext highlighter-rouge">Time</code> to server’s <code class="language-plaintext highlighter-rouge">MinTime</code> (usually 5 minutes)</li>
  <li>Monitor and log connection state transitions</li>
  <li>Implement circuit breakers for repeated connection failures</li>
  <li>Use connection pooling for high-throughput applications</li>
  <li>Design for pod rotation with proper service discovery</li>
</ul>

<h3 id="donts">Don’ts</h3>
<ul>
  <li>Set aggressive ping intervals without coordinating with server operators</li>
  <li>Ignore <code class="language-plaintext highlighter-rouge">ENHANCE_YOUR_CALM</code> errors in logs</li>
  <li>Assume connections will always remain healthy</li>
  <li>Overlook keepalive configuration in production environments</li>
  <li>Connect directly to pod IPs instead of service names</li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>Properly configured keepalive mechanisms are essential for robust gRPC services. By understanding the interplay between client configurations and server enforcement policies, you can create resilient microservice architectures that gracefully handle network disruptions and container orchestration events.</p>

<p>Remember these key takeaways:</p>

<ol>
  <li>gRPC is built directly on HTTP/2, leveraging its advanced features</li>
  <li>Respect the server’s <code class="language-plaintext highlighter-rouge">MinTime</code> policy (usually 5 minutes)</li>
  <li>ENHANCE_YOUR_CALM errors indicate policy violations but don’t cause immediate connection termination</li>
  <li>Design clients to handle pod rotation in containerized environments</li>
  <li>Implement comprehensive connection health monitoring and recovery mechanisms</li>
</ol>

<p>By following these guidelines, your gRPC services will maintain optimal connectivity through infrastructure changes, network disruptions, and deployment events.</p>

<p>This blog was originally posted on <a href="https://medium.com/@seomisw/image-dataset-for-litter-detection-7f1cab9e7fa1" target="_blank">Medium</a>–be sure to follow and clap!</p>

<hr />

<p><strong>Further Reading:</strong></p>
<ul>
  <li><a href="https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md">gRPC Connectivity Semantics and API</a></li>
  <li><a href="https://httpwg.org/specs/rfc7540.html#ErrorCodes">HTTP/2 Specification: Error Codes</a></li>
  <li><a href="https://github.com/grpc/proposal/blob/master/A6-client-retries.md">gRPC Retry Design</a></li>
  <li><a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination">Kubernetes: Termination of Pods</a></li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[Client (🖥️) sends rapid ❤️ pings → Server (🛡️) blocks with "5m min" shield → "ENHANCE_YOUR_CALM" error badge.]]></summary></entry><entry><title type="html">HTTP Content Negotiation in Golang reverse proxy</title><link href="https://seomis.cc/blog/content-encoding-golang-transport" rel="alternate" type="text/html" title="HTTP Content Negotiation in Golang reverse proxy" /><published>2021-12-04T01:00:00+00:00</published><updated>2021-12-04T01:00:00+00:00</updated><id>https://seomis.cc/blog/content-encoding-golang-transport</id><content type="html" xml:base="https://seomis.cc/blog/content-encoding-golang-transport"><![CDATA[<h2><img src="/images/golang-transport/HTTPNego3.png" alt="" /></h2>

<h3 id="i-had-a-very-seemingly-simple-task-write-a-reverse-proxy-to-a-document-store">I had a very (seemingly) simple task. Write a reverse proxy to a document store.</h3>

<p>However an unexpected behavior made me dig deep about http content negotiation made by golang default implementation transport.</p>

<p>The original code (using <a href="https://github.com/gin-gonic/gin">gin</a>) was as simple as:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	remote:= some_remote_host
	proxy := httputil.NewSingleHostReverseProxy(remote)
	proxy.Director = func(req *http.Request) {
		req.Header = ctx.Request.Header
		req.Host = remote.Host
		req.URL.Scheme = remote.Scheme
		req.URL.Host = remote.Host
		req.URL.Path = ctx.Request.URL.Path
	}

	proxy.ServeHTTP(ctx.Writer, ctx.Request)

</code></pre></div></div>

<p>Via http 1.1, the reverse proxy worked ( the document was displayed correctly ) but the server exposed a panic stack strace.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>httputil: ReverseProxy read error during body copy: unexpected EOF

2021/12/04 16:47:40 [Recovery] 2021/12/04 - 16:47:40 panic recovered:
net/http: abort Handler
/usr/local/Cellar/go/1.17.2/libexec/src/net/http/httputil/reverseproxy.go:349 (0x12ba9a4)
(*ReverseProxy).ServeHTTP: panic(http.ErrAbortHandler)
</code></pre></div></div>

<p>WTF!?</p>

<p>…</p>

<p>Two unanswered questions:</p>

<ol>
  <li>
    <p>If httputil reverseproxy caused a panic while reading body, why is the body content displayed?</p>
  </li>
  <li>
    <p>why io.Read returned the unexpected EOF?</p>
  </li>
</ol>

<hr />

<h3 id="why-is-the-body-content-displayed">Why is the body content displayed?</h3>

<p>Looking at httputil reverseproxy copyBuffer source code, we understand why the content is still displayed:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// copyBuffer returns any write errors or non-EOF read errors, and the amount
// of bytes written.
func (p *ReverseProxy) copyBuffer(dst io.Writer, src io.Reader, buf []byte) (int64, error) {
	if len(buf) == 0 {
		buf = make([]byte, 32*1024)
	}
	var written int64
	for {
		nr, rerr := src.Read(buf)
		if rerr != nil <span class="err">&amp;&amp;</span> rerr != io.EOF <span class="err">&amp;&amp;</span> rerr != context.Canceled {
			p.logf("httputil: ReverseProxy read error during body copy: %v", rerr)
		}
		if nr &gt; 0 {
			nw, werr := dst.Write(buf[:nr])
			if nw &gt; 0 {
				written += int64(nw)
			}
			if werr != nil {
				return written, werr
			}
			if nr != nw {
				return written, io.ErrShortWrite
			}
		}
		if rerr != nil {
			if rerr == io.EOF {
				rerr = nil
			}
			return written, rerr
		}
	}
}
</code></pre></div></div>

<p>Read is called for the entire document returning Unexpected EOF on the last read. In case of error, the buffer is still written, and we obtain the complete body.</p>

<hr />

<h3 id="why-did-ioread-return-unexpectedeof">Why did io.Read return UnexpectedEOF?</h3>

<p>First let’s find out which reader was chosen by default transport.</p>

<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding">Accept-Encoding</a> request HTTP header indicates the content encoding (usually a compression algorithm) that the client can understand. The server uses content negotiation to select one of the proposal and informs the client of that choice with the Content-Encoding response header.</p>

<p>The request headers from the browser that performed the call are the following:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8

Accept-Language: pt-PT,pt;q=0.8,en;q=0.5,en-US;q=0.3

Accept-Encoding: gzip, deflate
</code></pre></div></div>

<p>The reader is either <a href="https://pkg.go.dev/compress/gzip">compress/gzip</a> or <a href="https://pkg.go.dev/compress/flate">compress/flate</a>.</p>

<p>Reverse proxy is using http.DefaultTransport which on <a href="https://github.com/golang/go/blob/master/src/net/http/transport.go#L2190">line 2190</a> confirms the choice of gzip as reader.</p>

<p>Gzip Reader implementation can be seen below:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Read implements io.Reader, reading uncompressed bytes from its underlying Reader.
func (z *Reader) Read(p []byte) (n int, err error) {
	if z.err != nil {
		return 0, z.err
	}

	n, z.err = z.decompressor.Read(p)
	z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n])
	z.size += uint32(n)
	if z.err != io.EOF {
		// In the normal case we return here.
		return n, z.err
	}

	// Finished file; check checksum and size.
	if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil {
		z.err = noEOF(err)

		return n, z.err
	}

	digest := le.Uint32(z.buf[:4])
	size := le.Uint32(z.buf[4:8])
	if digest != z.digest || size != z.size {
		z.err = ErrChecksum
		return n, z.err
	}
	z.digest, z.size = 0, 0

	// File is ok; check if there is another.
	if !z.multistream {
		return n, io.EOF
	}
	z.err = nil // Remove io.EOF

	if _, z.err = z.readHeader(); z.err != nil {
		return n, z.err
	}

	// Read from next file, if necessary.
	if n &gt; 0 {
		return n, nil
	}
	return z.Read(p)
}
</code></pre></div></div>

<p>The <strong>readHeader</strong> method sparked my attention.</p>

<p>Surely, if we requested file in gzip format, it must comply with <a href="https://datatracker.ietf.org/doc/html/rfc1952#page-5">gzip spec</a>.</p>

<p>However… Several prints later… We confirm that the server didn’t comply with the given ‘Accept-Encoding’ of the client!</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// readHeader reads the GZIP header according to section 2.3.1.
// This method does not set z.err.
func (z *Reader) readHeader() (hdr Header, err error) {
	n, err := io.ReadFull(z.r, z.buf[:10])
	if err != nil {
		// RFC 1952, section 2.2, says the following:
		//	A gzip file consists of a series of "members" (compressed data sets).
		//
		// Other than this, the specification does not clarify whether a
		// "series" is defined as "one or more" or "zero or more". To err on the
		// side of caution, Go interprets this to mean "zero or more".
		// Thus, it is okay to return io.EOF here.
		fmt.Println("READ FULL ERROR ", err, z.buf[0] != gzipID1, z.buf[1] != gzipID2, z.buf[2] != gzipDeflate)

		return hdr, err
	}
</code></pre></div></div>

<p>The puzzling <strong>unexpected EOF</strong> is returned by read header call to <strong>io.ReadFull</strong>!</p>

<p>None of the members follow gzip file format specification!</p>

<p>This <a href="https://go.dev/play/p/l2HmrW216OD">small snippet</a> confirms that an invalid binary format is detected using readHeader, which indeed returns unexpected EOF.</p>

<hr />

<h3 id="correcting-the-reverse-proxy">Correcting the reverse proxy</h3>

<p>Unfortunately, we cannot change the server response so we will fix this panic on the reverse proxy.</p>

<p>First let’s try to remove <strong>Accept-Encoding</strong> header on <strong>proxy.Director</strong>.</p>

<p>Unfortunately, this approach does nothing.</p>

<p>The default choice of <a href="https://go.dev/src/net/http/transport.go#L2546">http.DefaultTransport</a> is still gzip as seen below :</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	// Ask for a compressed version if the caller didn't set their
	// own value for Accept-Encoding. We only attempt to
	// uncompress the gzip stream if we were the layer that
	// requested it.
	requestedGzip := false
	if !pc.t.DisableCompression <span class="err">&amp;&amp;</span>
		req.Header.Get("Accept-Encoding") == "" <span class="err">&amp;&amp;</span>
		req.Header.Get("Range") == "" <span class="err">&amp;&amp;</span>
		req.Method != "HEAD" {
		// Request gzip only, not deflate. Deflate is ambiguous and
		// not as universally supported anyway.
		// See: https://zlib.net/zlib_faq.html#faq39
		//
		// Note that we don't request this for HEAD requests,
		// due to a bug in nginx:
		//   https://trac.nginx.org/nginx/ticket/358
		//   https://golang.org/issue/5522
		//
		// We don't request gzip if the request is for a range, since
		// auto-decoding a portion of a gzipped document will just fail
		// anyway. See https://golang.org/issue/8923
		requestedGzip = true
		req.extraHeaders().Set("Accept-Encoding", "gzip")
	}


</code></pre></div></div>

<p>We are left with two choices:</p>

<ul>
  <li>
    <p>setting <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding#directives">Accept-Encoding Directive</a> as identity, which won’t modify or compress the response server body.</p>
  </li>
  <li>
    <p><a href="https://go.dev/src/net/http/transport.go#L173">disable compression of Transport</a>.</p>
  </li>
</ul>

<h3 id="both-worked-yes-another-panic-avoided">Both worked… YES! Another panic avoided!</h3>

<p>My inner curiosity is satisfied! This was fun :)</p>

<hr />

<p>This blog was originally posted on <a href="https://medium.com/@seomisw/http-content-negotiation-in-golang-reverse-proxy-6191f14ecdcb" target="_blank">Medium</a>–be sure to follow and clap!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Understanding golang transport behavior for http content negotiation.]]></summary></entry><entry><title type="html">Bash + ElasticSearch MultiSearch</title><link href="https://seomis.cc/blog/kibana-surrounding-bash" rel="alternate" type="text/html" title="Bash + ElasticSearch MultiSearch" /><published>2021-04-10T01:00:00+00:00</published><updated>2021-04-10T01:00:00+00:00</updated><id>https://seomis.cc/blog/kibana-surrounding-bash</id><content type="html" xml:base="https://seomis.cc/blog/kibana-surrounding-bash"><![CDATA[<p><img src="/images/elastic-bash/shell-script-logo.jpg" alt="" /></p>

<hr />

<h3 id="correlating-logs-on-elasticsearch-using-kibana-is-usually-pretty-easy">Correlating logs on ElasticSearch using Kibana is usually pretty easy.</h3>

<p>In Distributed Systems, if <strong>System Y</strong> performs a request to <strong>System X</strong>, you can use attributes like <strong>transaction_id</strong>, <strong>trace_id</strong> and <strong>span_id</strong> to navigate all logs belonging to a particular trace, and vice-versa.</p>

<p>But sometimes you have systems interacting which have <strong>no good log correlation</strong>. You could be still in MVP phase, or the system calling is a legacy system that no one want to touch, or even that the logs between systems are not structured in a way that is easy to query data.</p>

<p>You’ll find yourself looking in surrounding documents near the log you are interested in, or blindingly looking in some other system logs for some information that helps you understand some situation… and if your systems produce <strong>a lot</strong> of log data, finding the information you want can easily feel like finding a needle on a waystack.</p>

<p>Well… i found myself in this situation this week ¯(シ)/¯ .</p>

<p>Fortunately, the information i was searching was always on the surrounding documents of some specific log.</p>

<blockquote>
  <p>So i thought: Ok, I’ll spend 20 min of my weekend automating this.</p>
</blockquote>

<hr />
<h2 id="the-basic-idea">The basic idea</h2>

<p>Should be simple enough: Open browser developer tools, click the Kibana log link of <code class="language-plaintext highlighter-rouge">View Surrounding Documents</code>, <a href="https://everything.curl.dev/usingcurl/copyas">copy as curl</a>. Tune some of the request fields, perform the request and  use <a href="https://github.com/stedolan/jq">jq</a> to look up the fields i want.</p>

<p>The original curl (without headers) is similar to this one:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl 'https://<span class="nt">&lt;some_endpoint&gt;</span>/_msearch?rest_total_hits_as_int=true<span class="err">&amp;</span>ignore_throttled=true'
--data-raw $'{"index":"logstash-default*","ignore_unavailable":true,
"preference":1618072435228}\n{"size":5,"search_after":[1618071886078,23742571],
"sort":[{"@timestamp":{"order":"asc","unmapped_type":"boolean"}},{"_doc":{"order":"desc","unmapped_type":"boolean"}}],
"version":true,"_source":{"excludes":[]},"stored_fields":["*"],"script_fields":{},
"docvalue_fields":[{"field":"@timestamp","format":"date_time"}],
"query":{"bool":{"must":[{"constant_score":{"filter":{"range":{"@timestamp":{"format":"epoch_millis","gte":1618071886078,"lte":1618158286078}}}}}],
"filter":[],"should":[],"must_not":[]}},"timeout":"30000ms"}\n{"index":"logstash-default*","ignore_unavailable":true,"preference":1618072435228}\n
{"size":5,"search_after":[1618071886078,23742571],"sort":[{"@timestamp":{"order":"desc","unmapped_type":"boolean"}},
{"_doc":{"order":"asc","unmapped_type":"boolean"}}],"version":true,
"_source":{"excludes":[]},"stored_fields":["*"],"script_fields":{},
"docvalue_fields":[{"field":"@timestamp","format":"date_time"}],
"query":{"bool":{"must":[{"constant_score":{"filter":{"range":{
"@timestamp":{"format":"epoch_millis","lte":1618071886078,"gte":1617985486078}}}}}],
"filter":[],"should":[],"must_not":[]}},"timeout":"30000ms"}\n'
</code></pre></div></div>

<p>Ok, this big curl thing that you probably cannot see in your mobile phone screen, uses <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html">multisearch</a> to execute several searches with a single API request.</p>

<p>The request makes use of the <a href="http://ndjson.org/">newline delimited JSON</a> format (NDJSON). In simpler terms, it follows the following structure:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Header\n
Body\n
Header\n
Body\n
</code></pre></div></div>

<p>This is important and justifies why the curl data raw is <strong>–data-raw $’{}’</strong>. instead of <strong>–data-raw ‘{}’</strong>.</p>

<p>The notation $’…’ is a special form of quoting a string. Strings that are scanned for <a href="https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting">ANSI C like escape sequences</a>.</p>

<p>So in a quick look i could see that two headers and two body, so it is performing <strong>two</strong> searches.</p>

<p>Each header contains the following information:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
	</span><span class="nl">"index"</span><span class="p">:</span><span class="w"> </span><span class="s2">"logstash-default*"</span><span class="p">,</span><span class="w">
	</span><span class="nl">"ignore_unavailable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
	</span><span class="nl">"preference"</span><span class="p">:</span><span class="w"> </span><span class="mi">12353564645</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li>index: the index we are using</li>
  <li>preference: preference of which shard copies on which to execute the search</li>
  <li>ignore_unavailable: missing or closed indices are not included in the response if true (which is the case).</li>
</ul>

<p>The two bodies have a similar format:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"size"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w">
  </span><span class="nl">"search_after"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="mi">1618071886078</span><span class="p">,</span><span class="w">
    </span><span class="mi">23742571</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"sort"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"@timestamp"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"order"</span><span class="p">:</span><span class="w"> </span><span class="s2">"asc"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"unmapped_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"boolean"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"_doc"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"order"</span><span class="p">:</span><span class="w"> </span><span class="s2">"desc"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"unmapped_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"boolean"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"_source"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"excludes"</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"stored_fields"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="s2">"*"</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"script_fields"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span><span class="w">
  </span><span class="nl">"docvalue_fields"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"@timestamp"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"date_time"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"query"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"bool"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"must"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"constant_score"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nl">"filter"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
              </span><span class="nl">"range"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"@timestamp"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                  </span><span class="nl">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"epoch_millis"</span><span class="p">,</span><span class="w">
                  </span><span class="nl">"gte"</span><span class="p">:</span><span class="w"> </span><span class="mi">1618071886078</span><span class="p">,</span><span class="w">
                  </span><span class="nl">"lte"</span><span class="p">:</span><span class="w"> </span><span class="mi">1618158286078</span><span class="w">
                </span><span class="p">}</span><span class="w">
              </span><span class="p">}</span><span class="w">
            </span><span class="p">}</span><span class="w">
          </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"filter"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span><span class="w">
      </span><span class="nl">"should"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span><span class="w">
      </span><span class="nl">"must_not"</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"timeout"</span><span class="p">:</span><span class="w"> </span><span class="s2">"30000ms"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>The important fields are the following:</p>

<ul>
  <li>size : the number of hits to return</li>
  <li>search_after: works as a live cursor, where we have [offset,limit]</li>
  <li>sort : we are sorting by timestamp asc</li>
  <li>query: it’s using a range query to return documents within the provided range.</li>
</ul>

<p>Now it is clear what the curl is doing: it is using the unix timestamp of a particular record to retrieve the 5 previous and following records.</p>

<p><em>So, if we give it the unix timestamp of the record, we should be able to obtain the neibouring information.</em></p>

<hr />
<h3 id="now-that-we-understand-the-request-we-need-to-retrieve-the-information-we-are-looking-for-on-surrounding-docs">Now that we understand the request, we need to retrieve the information we are looking for on surrounding docs.</h3>

<p>For that, i have choosen the following <a href="https://github.com/stedolan/jq">jq</a> filter:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jq '.responses[0].hits.hits[] | ._source.payload.fields.&lt;field_i_am_looking_for&gt;'
</code></pre></div></div>

<p>we use the first array index of responses and we will return all of the elements of an array <strong>hits</strong>. We use the <a href="https://stedolan.github.io/jq/manual/#Basicfilters">Pipe</a> operator to run a filter for each of those results. In my case i want to retrieve fields _source.payload.fields.<the field="" that="" i="" am="" looking="" for="">_.</the></p>

<h3 id="good-now-we-are-ready-to-write-some-bash">Good! Now, we are ready to write some bash.</h3>

<p>I want to receive as input three fields:</p>

<ul>
  <li>an unix timestamp used to look around.</li>
  <li>the number of records i’ll want to look around.</li>
  <li>the field i am looking for.</li>
</ul>

<p>To handle user input, i’ve written the following:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helpFunction<span class="o">()</span>
<span class="o">{</span>
   <span class="nb">echo</span> <span class="s2">""</span>
   <span class="nb">echo</span> <span class="s2">"Usage: </span><span class="nv">$0</span><span class="s2"> --sort &lt;sort_id&gt; --around &lt;number_of_entries&gt; --field &lt;the field name i am looking for&gt;"</span>
   <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\t</span><span class="s2">--sort sort field found on json entry"</span>
   <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\t</span><span class="s2">--size number of surrounding documents"</span>
   <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\t</span><span class="s2">--field field you are looking"</span>
   <span class="nb">exit </span>1
<span class="o">}</span>

<span class="nv">ARGUMENT_LIST</span><span class="o">=(</span>
    <span class="s2">"sort"</span>
    <span class="s2">"around"</span>
    <span class="s2">"field"</span>
<span class="o">)</span>


<span class="c"># read arguments</span>
<span class="nv">opts</span><span class="o">=</span><span class="si">$(</span>getopt <span class="se">\</span>
    <span class="nt">--longoptions</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">printf</span> <span class="s2">"%s:,"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">ARGUMENT_LIST</span><span class="p">[@]</span><span class="k">}</span><span class="s2">"</span><span class="si">)</span><span class="s2">"</span> <span class="se">\</span>
    <span class="nt">--name</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">basename</span> <span class="s2">"</span><span class="nv">$0</span><span class="s2">"</span><span class="si">)</span><span class="s2">"</span> <span class="se">\</span>
    <span class="nt">--options</span> <span class="s2">""</span> <span class="se">\</span>
    <span class="nt">--</span> <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
<span class="si">)</span>

<span class="nb">eval set</span> <span class="nt">--</span><span class="nv">$opts</span>

<span class="k">while</span> <span class="o">[[</span> <span class="nv">$# </span><span class="nt">-gt</span> 0 <span class="o">]]</span><span class="p">;</span> <span class="k">do
    case</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="k">in</span>
        <span class="nt">--sort</span><span class="p">)</span>
            <span class="nv">argOne</span><span class="o">=</span><span class="nv">$2</span>
            <span class="nb">shift </span>2
            <span class="p">;;</span>

        <span class="nt">--around</span><span class="p">)</span>
            <span class="nv">argTwo</span><span class="o">=</span><span class="nv">$2</span>
            <span class="nb">shift </span>2
            <span class="p">;;</span>

        <span class="nt">--field</span><span class="p">)</span>
            <span class="nv">argThree</span><span class="o">=</span><span class="nv">$2</span>
            <span class="nb">shift </span>2
            <span class="p">;;</span>
        <span class="nt">--</span><span class="p">)</span> <span class="nb">shift</span> <span class="p">;</span> <span class="nb">break</span> <span class="p">;;</span>
    <span class="k">esac</span>
<span class="k">done</span>

<span class="c"># Print helpFunction in case parameters are empty</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$argOne</span><span class="s2">"</span> <span class="o">]</span> <span class="o">||</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$argTwo</span><span class="s2">"</span> <span class="o">]||</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$argThree</span><span class="s2">"</span> <span class="o">]</span>
<span class="k">then
   </span><span class="nb">echo</span> <span class="s2">"Some or all of the parameters are empty"</span><span class="p">;</span>
   helpFunction
<span class="k">fi</span>

</code></pre></div></div>

<p>With sort input, we need to calculate the around timestamps:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">around_1</span><span class="o">=</span><span class="k">$((</span> <span class="nv">$argOne</span> <span class="o">+</span> <span class="m">86400000</span> <span class="k">))</span>
<span class="nv">around_2</span><span class="o">=</span><span class="k">$((</span> <span class="nv">$argOne</span> <span class="o">+</span> <span class="m">1985122</span> <span class="k">))</span>
</code></pre></div></div>

<p>And now we just need to call the curl!</p>

<p>Remeber that the notation $’…’ is being use on <code class="language-plaintext highlighter-rouge">data-raw</code>. That means that each user input variable added to the curl body needs the notations $’…’.</p>

<p>So this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl something <span class="nt">-d</span> <span class="s1">$'{"somefield1":'</span><span class="nv">$argOne</span><span class="s1">$',"somefield2":'</span><span class="nv">$argTwo</span><span class="s1">$'}'</span>
</code></pre></div></div>

<p>Instead of this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl something <span class="nt">-d</span> <span class="s1">$'{"somefield1":'</span><span class="nv">$argOne</span><span class="s1">',"somefield2":'</span><span class="nv">$argTwo</span><span class="s1">'}'</span>
</code></pre></div></div>

<p>Did you notice that single <strong>$</strong> after the variable and before the string?</p>

<p>So all together, the gist can be found <a href="https://gist.github.com/psimoesSsimoes/18d7e478d010994d9f5bb3907516dbf6">here</a></p>

<h3 id="and-the-main-lesson-is--words-of-the-form-string-are-treated-specially-the-word-expands-to-string-with-backslash-escaped-characters-replaced-as-specified-by-the-ansi-c-standard">And the main lesson is : Words of the form $’string’ are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard.</h3>
<hr />

<p>This blog was originally posted on <a href="https://seomisw.medium.com/bash-elasticsearch-multisearch-5123603af691" target="_blank">Medium</a>–be sure to follow and clap!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Trying to automate common searches on ElasticSearch using Bash.]]></summary></entry><entry><title type="html">My Advent Of Rust, Day 4</title><link href="https://seomis.cc/blog/my-advent-of-rust-day-4" rel="alternate" type="text/html" title="My Advent Of Rust, Day 4" /><published>2020-12-13T01:00:00+00:00</published><updated>2020-12-13T01:00:00+00:00</updated><id>https://seomis.cc/blog/my-advent-of-rust-day-4</id><content type="html" xml:base="https://seomis.cc/blog/my-advent-of-rust-day-4"><![CDATA[<p><img src="/images/advent-of-rust/advent_of_rust.png" alt="" /></p>

<h1 id="ive-always-considered-programming-challenges-a-fun-way-of-experimenting-new-languages">I’ve always considered programming challenges a fun way of experimenting new languages.</h1>

<p>For this edition of advent of code (2020), i decided i would give <a href="https://www.rust-lang.org/">Rust</a> a try.</p>

<p>Rust really makes your head spin a bit with supposedly trivial problems (and this is a good thing!).</p>

<p>This is mainly because programming in <strong>Rust requires you to think differently</strong>.</p>

<p>Replicating patterns that are common in other languages is tricky and sometimes quite hard or even impossible.</p>

<p>Day 4 was a good example, so let’s examine the <a href="https://adventofcode.com/2020/day/4">challenge</a>, which i will try to resume:</p>

<ul>
  <li>You have a big string input, containing representations of passports.</li>
  <li>On double newline, you have a passport.</li>
  <li>Each <strong>valid</strong> passport consists of the following fields: “byr”, “iyr”, “eyr”, “hgt”, “hcl”, “ecl”, “pid”.</li>
  <li>Find all valid passports.</li>
</ul>

<p>We’ll, first lets transform the input into something useful. This is the “similar” part of the Rust code to the rest of the other languages.</p>

<p>I’m sure there would be many ways of doing this but i have chosen:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">let</span> <span class="n">result</span> <span class="o">=</span> <span class="nn">fs</span><span class="p">::</span><span class="nf">read_to_string</span><span class="p">(</span><span class="s">"input_day_four.txt"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
 <span class="k">let</span> <span class="n">passports</span> <span class="o">=</span> <span class="n">result</span><span class="nf">.split</span><span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">"</span><span class="p">);</span>
</code></pre></div></div>

<p>so i have copied the input into a file (as a noobie, i prefered not to perform an http request :p ), read it to a String (unwrap to obtain the string is unsafe an discouraged, i know. but since i am controling the input, it is sufficient) and then split it to obtain each passport.</p>

<p>Why not doing it in one line like :</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   <span class="k">let</span> <span class="n">passports</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;&amp;</span><span class="nb">str</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nn">fs</span><span class="p">::</span><span class="nf">read_to_string</span><span class="p">(</span><span class="s">"input_day_four.txt"</span><span class="p">)</span>
        <span class="nf">.unwrap</span><span class="p">()</span>
        <span class="nf">.split</span><span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>
<p>Well… because using <strong>unwrap creates a temporary which is freed while still in use</strong>. And in Rust this means that i need to create a new variable if i want to continue.</p>

<p>So how do i verify which passports are valid?</p>

<p>Using a language like <a href="https://golang.org/">Go</a>, i would probably loop the separated strings, find the index of <code class="language-plaintext highlighter-rouge">:</code> and then try to delete an entry using the index. Then i would assert if the len of the map was equal to zero. If yes, then it is a valid passport. That could be represented as such:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">validPassportCounter</span> <span class="o">:=</span> <span class="m">0</span>
<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">passport</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">passports</span> <span class="p">{</span>
	<span class="n">control</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="k">struct</span><span class="p">{}{</span>
		<span class="s">"byr"</span><span class="o">:</span> <span class="k">struct</span><span class="p">{}{},</span>
		<span class="s">"iyr"</span><span class="o">:</span> <span class="k">struct</span><span class="p">{}{},</span>
		<span class="s">"eyr"</span><span class="o">:</span> <span class="k">struct</span><span class="p">{}{},</span>
		<span class="s">"hgt"</span><span class="o">:</span> <span class="k">struct</span><span class="p">{}{},</span>
		<span class="s">"hcl"</span><span class="o">:</span> <span class="k">struct</span><span class="p">{}{},</span>
		<span class="s">"ecl"</span><span class="o">:</span> <span class="k">struct</span><span class="p">{}{},</span>
		<span class="s">"pid"</span><span class="o">:</span> <span class="k">struct</span><span class="p">{}{},</span>
	<span class="p">}</span>

	<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">ch</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">passport</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">ch</span> <span class="o">==</span> <span class="sc">':'</span> <span class="p">{</span>
		  	<span class="nb">delete</span><span class="p">(</span><span class="n">control</span><span class="p">,</span> <span class="n">passport</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="m">3</span><span class="o">:</span><span class="n">i</span><span class="p">])</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">control</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span> <span class="p">{</span>
		<span class="n">validPassportCounter</span><span class="o">++</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>another way would be to split whitespace an find the strings starting with the desired fields like so:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">validPassportCounter</span> <span class="o">:=</span> <span class="m">0</span>
<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">passport</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">passports</span> <span class="p">{</span>
        <span class="n">control</span> <span class="o">:=</span> <span class="m">0</span>
	<span class="n">fields</span> <span class="o">:=</span> <span class="n">strings</span><span class="o">.</span><span class="n">Fields</span><span class="p">(</span><span class="n">passport</span><span class="p">)</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">field</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">fields</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s">"byr"</span><span class="p">)</span> <span class="o">||</span> <span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s">"iyr"</span><span class="p">)</span> <span class="o">||</span>
			 <span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s">"eyr"</span><span class="p">)</span> <span class="o">||</span> <span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s">"hgt"</span><span class="p">)</span> <span class="o">||</span> 				<span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s">"hcl"</span><span class="p">)</span> <span class="o">||</span>
				<span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s">"ecl"</span><span class="p">)</span> <span class="o">||</span> <span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s">"pid"</span><span class="p">)</span> <span class="p">{</span>
				<span class="n">control</span><span class="o">++</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="n">control</span> <span class="o">==</span> <span class="m">7</span> <span class="p">{</span>
		<span class="n">validPassportCounter</span><span class="o">++</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Using these patterns proved to be quite challenging in Rust. I kept fighting the compiler, and the compiler kept winning.</p>

<blockquote>
  <p>So i went back to sketching… what was i really trying to do?</p>
</blockquote>

<p>I have a vector of references to strings to which i wanted to filter the ones containing the right values and then count the collected values.</p>

<p>Looking at <a href="https://doc.rust-lang.org/std/iter/struct.Filter.html#method.count">Iter</a> i found that using an iterator i could <a href="https://doc.rust-lang.org/std/iter/struct.Filter.html">filter</a> elements with a predicate and then <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.count">count</a> the filtered entries.</p>

<p>Horaay!</p>

<p>So i am on to something. I wrote:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">valid_passports</span> <span class="o">=</span> <span class="n">passports</span>
        <span class="nf">.filter</span><span class="p">()</span>
        <span class="nf">.count</span><span class="p">();</span>
</code></pre></div></div>
<p>So now i only need a predicate that filters the strings i need!</p>

<p>the predicate could be similar to the second golang approach:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">check_validity_part_1</span><span class="p">(</span><span class="n">passport</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">bool</span> <span class="p">{</span>
	<span class="k">let</span> <span class="n">fields</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[</span><span class="s">"byr"</span><span class="p">,</span> <span class="s">"iyr"</span><span class="p">,</span> <span class="s">"eyr"</span><span class="p">,</span> <span class="s">"hgt"</span><span class="p">,</span> <span class="s">"hcl"</span><span class="p">,</span> <span class="s">"ecl"</span><span class="p">,</span> <span class="s">"pid"</span><span class="p">];</span>
	<span class="n">fields</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.all</span><span class="p">(|</span><span class="n">field</span><span class="p">|</span> <span class="p">{</span>
		<span class="n">passport</span>
		<span class="nf">.split_ascii_whitespace</span><span class="p">()</span>
		<span class="nf">.any</span><span class="p">(|</span><span class="n">passport_field</span><span class="p">|</span> <span class="n">passport_field</span><span class="nf">.starts_with</span><span class="p">(</span><span class="n">field</span><span class="p">))</span>
	<span class="p">})</span>
<span class="p">}</span>
</code></pre></div></div>
<p>so again i ask for my new BFF <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html">Iterator</a>, which holds an <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all">all</a> method that tests if every element of passport verifies a predicate.</p>

<p>The predicate i want is for each <strong>field of a passport</strong>, determine if the passport_field starts with any of the values of <strong>fields</strong>.</p>

<p>For that, i’ve use a  <a href="https://doc.rust-lang.org/std/primitive.str.html#method.split_ascii_whitespace">split_ascii_whitespace</a> to obtain the passport fields, and <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.any">any</a> to verify passport correctness.</p>

<p>Voila!</p>

<p>Now gluing it all together…  <strong>it compiles!!!!! YES!! We are the champions!!!!</strong></p>

<p>i just had to make every passport pass the predicate <strong>check_validity_part_1</strong> that i wrote previously:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">result</span> <span class="o">=</span> <span class="nn">fs</span><span class="p">::</span><span class="nf">read_to_string</span><span class="p">(</span><span class="s">"input_day_four.txt"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>

<span class="k">let</span> <span class="n">passports</span> <span class="o">=</span> <span class="n">result</span><span class="nf">.split</span><span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">"</span><span class="p">);</span>

<span class="k">let</span> <span class="n">valid_passports</span> <span class="o">=</span> <span class="n">passports</span>
        <span class="nf">.filter</span><span class="p">(|</span><span class="n">passport</span><span class="p">|</span> <span class="nf">check_validity_part_1</span><span class="p">(</span><span class="n">passport</span><span class="p">))</span>
        <span class="nf">.count</span><span class="p">();</span>

<span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">valid_passports</span><span class="p">);</span>
</code></pre></div></div>
<p>and this piece gives the correct input to the first challenge of the 4 day :)</p>

<hr />

<blockquote>
  <p>Some lessons to myself: don’t fight the compiler. If your approach/pattern is not working, it is probably because you probably cannot use this same pattern using Rust. Stop, re-evaluate, read the documentation, and surely you’ll find a way of solving the problem.</p>
</blockquote>

<h3 id="if-this-was-the-optimal-approach-well-that-should-be-re-evaluated-once-i-have-a-better-knowledge-of-rust-">If this was the optimal approach… well, that should be re-evaluated, once i have a better knowledge of Rust :)</h3>

<p>This blog was originally posted on <a href="https://seomisw.medium.com/my-advent-of-rust-day-4-bc3a9e76a85b" target="_blank">Medium</a>–be sure to follow and clap!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Notes on day 4 of advent of code made in Rust.]]></summary></entry><entry><title type="html">Image Dataset for Litter Detection</title><link href="https://seomis.cc/blog/taco-dataset" rel="alternate" type="text/html" title="Image Dataset for Litter Detection" /><published>2020-05-17T01:00:00+00:00</published><updated>2020-05-17T01:00:00+00:00</updated><id>https://seomis.cc/blog/taco-dataset</id><content type="html" xml:base="https://seomis.cc/blog/taco-dataset"><![CDATA[<p><img src="/images/taco/taco.gif" alt="" /></p>

<h1 id="today-i-want-to-talk-a-bit-about-a-project-from-the-mind-of-the-idealist-and-wizard-pedro-proença">Today i want to talk a bit about a project from the mind of the idealist and wizard <a href="https://pedropro.github.io/">Pedro Proença</a>.</h1>

<p>It is called <a href="http://tacodataset.org/">TACO</a>, which stands for Trash Annotations in Context, and it is an open image dataset for litter detection, similar to <a href="http://cocodataset.org/">COCO object segmentation</a>. It contains photos of litter taken under diverse environments, from tropical beaches to London streets. These images are manually labeled and segmented according to a hierarchical taxonomy to train and evaluate object detection algorithms.</p>

<h2 id="why-is-taco-needed">Why is TACO needed?</h2>

<p>Humans have been trashing planet Earth from the bottom of <a href="https://www.nationalgeographic.com/news/2018/05/plastic-bag-mariana-trench-pollution-science-spd/">Mariana trench</a> to <a href="https://www.livescience.com/63061-how-much-trash-mount-everest.html">Mount Everest</a>. <a href="http://www3.weforum.org/docs/WEF_The_New_Plastics_Economy.pdf">Every minute, at least 15 tonnes of plastic waste leak into the ocean</a>, that is equivalent to the capacity of one garbage truck. We have all seen the impact of this behaviour to wildlife on images of turtles choking on plastic bags and birds filled with bottle caps. Recent studies have also found microplastics in human stools. These should be kept in the recycling chain not in our food chain.</p>

<p>We believe AI has an important role to play. Think of drones surveying trash, robots picking up litter, anti-littering video surveillance and AR to educate and help humans to separate trash. That is our vision. All of this is now possible with the recent advances of <a href="https://www.youtube.com/watch?v=Cgxsv1riJhI">deep learning</a>. However, to learn accurate trash detectors, deep learning needs many <a href="https://www.youtube.com/watch?v=40riCqvRoMs">annotated images</a>. While there are a few other trash datasets, we believe these are not enough and therefore we created TACO.</p>

<h2 id="taco-features">TACO Features</h2>

<ul>
  <li>Object segmentation. Typically used bounding boxes are not enough for certain tasks, e.g., robotic grasping</li>
  <li>Images under free licence. You can do whatever you want with TACO as long as you cite us.</li>
  <li>Background annotation. TACO covers many environments which are tagged for convenience.</li>
  <li>Object context tag. Not all objects in TACO are strictly litter. Some objects are handheld or not even trash yet. Thus, objects are tagged based on context.</li>
</ul>

<h2 id="the-dataset">The Dataset</h2>

<p>TACO  contains  high  resolution  images,  taken  mostly  by  mobile  phones.  These  are  managed  and stored by Flickr, whereas our server manages the annotations and  runs  periodically  a  crawler  to  collect  more  potential images of litter. Images are labeled with the scene tags,  to  describe  their  background  –  these  are  not mutually exclusive – and litter instances are segmented and labeled using <a href="http://tacodataset.org/taxonomy">a hierarchical taxonomy with 60 categories of litter  which  belong  to  28  super  (top)  categories  ,including  a  special  category:Unlabeled litterforobjects  that  are  either  ambiguous  or  not  covered  by  the other categories</a>. This is fundamentally different from other datasets  (e.g.  COCO)  where  distinction  between  classes  is key.  Here, all  objects  can  be in  fact  classified as  one  class: <strong>litter</strong>.  Furthermore,  it  may  be  impossible  to  distinguish visually  between  two  classes,  e.g.,  plastic  bottle  and  glassbottle. Given this ambiguity and the class imbalance, classes can be rearranged to suit a particular task.</p>

<h3 id="how-can-one-help">How can one help?</h3>

<ul>
  <li>Annotations are key to improve the dataset and TACO is officially open for <a href="http://tacodataset.org/annotate">new annotations</a>.</li>
  <li>Litter image submission is also important and can be done <a href="http://tacodataset.org/upload">here</a> or to Flickr following our <a href="http://tacodataset.org/flickr_instructions">instructions</a>.</li>
  <li>Use dataset: If you are interested in machine learning, check out <a href="https://github.com/pedropro/TACO">our repo</a> and start using this dataset in your experiments. We would love to hear about your results.</li>
  <li>Feedback is appreciated. Let us know if you spot any issue with the dataset or our tools.</li>
</ul>

<p>This blog was originally posted on <a href="https://medium.com/@seomisw/image-dataset-for-litter-detection-7f1cab9e7fa1" target="_blank">Medium</a>–be sure to follow and clap!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Open image dataset of waste in the wild.]]></summary></entry><entry><title type="html">Easy search in VIM</title><link href="https://seomis.cc/blog/vim-search" rel="alternate" type="text/html" title="Easy search in VIM" /><published>2020-05-09T00:00:00+00:00</published><updated>2020-05-09T00:00:00+00:00</updated><id>https://seomis.cc/blog/vim-search</id><content type="html" xml:base="https://seomis.cc/blog/vim-search"><![CDATA[<p><img src="/images/vim_search/vimgrep.gif" alt="" /></p>

<h2 id="easy-search-in-vim">Easy search in VIM</h2>

<p>Every developer needs a fast way to search for a current word in multiple files.</p>

<p>As a <a href="https://github.com/vim" target="_blank">vim</a> user the way i used to do it would be in the form :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:Ack! &lt; word &gt; &lt; directory_where_i_want_to_search &gt;
</code></pre></div></div>

<p>Surely there must be a better way!</p>

<p>That way was presented to me by my vim partner in crime, Mr João Seabra.
He wrote a small <a href="https://learnvimscriptthehardway.stevelosh.com/chapters/23.html" target="_blank">vim function</a> which i find particularly useful for my daily workflow:</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span><span class="p">!</span> <span class="nv">s:GrepOperator</span><span class="p">()</span>
    <span class="k">let</span> wordUnderCursor <span class="p">=</span> <span class="nb">expand</span><span class="p">(</span><span class="s2">"&lt;cword&gt;"</span><span class="p">)</span>
    <span class="k">silent</span> <span class="nb">execute</span> <span class="s2">"Ack! "</span> <span class="p">.</span> <span class="nb">shellescape</span><span class="p">(</span>wordUnderCursor<span class="p">)</span> <span class="p">.</span> <span class="s2">" "</span> <span class="p">.</span> <span class="nv">g:var_default</span>
    <span class="k">copen</span>
    <span class="k">redraw</span><span class="p">!</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>Let’s understand how it works:</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> wordUnderCursor <span class="p">=</span> <span class="nb">expand</span><span class="p">(</span><span class="s2">"&lt;cword&gt;"</span><span class="p">)</span>
</code></pre></div></div>

<p>we start by declaring a variable which will hold the word under cursor</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">silent</span> <span class="nb">execute</span> <span class="s2">"Ack! "</span> <span class="p">.</span> <span class="nb">shellescape</span><span class="p">(</span>wordUnderCursor<span class="p">)</span> <span class="p">.</span> <span class="s2">" "</span> <span class="p">.</span> <span class="nv">g:var_default</span>
</code></pre></div></div>

<p>we execute the shell command silently (in my case i like to use a code searching tool similar to ack called the_silver_searcher) providing the wordUnderCursor and the directory where we want where we want to search (which is stored in a global variable var_default)</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">copen</span>
<span class="k">redraw</span><span class="p">!</span>
</code></pre></div></div>

<p>we open the quickfix window and we force a screen refresh</p>

<p>Note that you could any grep-like tool you prefer instead of <strong>Ack</strong>.</p>

<p>I also recomend reading <strong>help cword</strong> to get more options. For my vimrc, I needed <strong>cWORD</strong> to grab the whitespace delimited text under the cursor.</p>

<h2 id="how-do-you-fill-the-global-variable-with-the-directory-to-search-in">How do you fill the global variable with the directory to search in?</h2>

<p>In my case i find it useful to set it to the <strong>current working directory</strong>. That can be achieved by setting in your vimrc the following line:</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">g:var_default</span> <span class="p">=</span> <span class="nb">getcwd</span><span class="p">()</span>
</code></pre></div></div>

<h2 id="how-do-we-call-the-function-quickly">How do we call the function quickly?</h2>

<p>for that we need a mapping!  That is achieved with the following lines:</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vnoremap <span class="p">&lt;</span>leader<span class="p">&gt;</span>z <span class="p">:&lt;</span><span class="k">c</span><span class="p">-</span><span class="k">u</span><span class="p">&gt;</span><span class="k">call</span> <span class="p">&lt;</span>SID<span class="p">&gt;</span>GrepOperator<span class="p">()&lt;</span><span class="k">cr</span><span class="p">&gt;</span>
<span class="nb">noremap</span> <span class="p">&lt;</span>leader<span class="p">&gt;</span>z <span class="p">:&lt;</span><span class="k">c</span><span class="p">-</span><span class="k">u</span><span class="p">&gt;</span><span class="k">call</span> <span class="p">&lt;</span>SID<span class="p">&gt;</span>GrepOperator<span class="p">()&lt;</span><span class="k">cr</span><span class="p">&gt;</span>
</code></pre></div></div>

<p>with these lines i can call the vim function in normal and visual mode. In my case, you can see that i map it for &lt; leader &gt; z.</p>

<p>To wrap it up, a fast way to navigate the result documents can be done with the following mappings:</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nnoremap <span class="p">&lt;</span>leader<span class="p">&gt;</span><span class="k">j</span> <span class="p">:</span><span class="k">cnext</span><span class="p">&lt;</span>CR<span class="p">&gt;</span>
nnoremap <span class="p">&lt;</span>leader<span class="p">&gt;</span><span class="k">k</span> <span class="p">:</span><span class="k">cprevious</span><span class="p">&lt;</span>CR<span class="p">&gt;</span>
</code></pre></div></div>

<p>using <strong>&lt; leader &gt;j</strong> , we navigate to the next result.</p>

<p>using <strong>&lt; leader &gt;k</strong> , we navigate to the previous result.</p>

<p>That’s it! Now we have a quick and practical way of searching words in vim!</p>

<h3 id="do-you-have-a-differentbetter-way-of-achieving-the-same-result">Do you have a different/better way of achieving the same result?</h3>
<h3 id="i-would-love-to-hear-about-it-">I would love to hear about it :)</h3>

<p>This blog was originally posted on <a href="https://link.medium.com/QyA2B23on6" target="_blank">Medium</a>–be sure to follow and clap!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[VIM + Functions + ACK == WIN!.]]></summary></entry></feed>