<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sylvain TIASSOU</title>
    <description>The latest articles on DEV Community by Sylvain TIASSOU (@sylvain_tiassou_61317f8f2).</description>
    <link>https://dev.to/sylvain_tiassou_61317f8f2</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4246292%2F6bcf6a7a-7690-499a-8bb2-2660261acd2a.png</url>
      <title>DEV Community: Sylvain TIASSOU</title>
      <link>https://dev.to/sylvain_tiassou_61317f8f2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sylvain_tiassou_61317f8f2"/>
    <language>en</language>
    <item>
      <title>Building a Safe-by-Design HTTP Telemetry Crate in Rust</title>
      <dc:creator>Sylvain TIASSOU</dc:creator>
      <pubDate>Sun, 15 Nov 2026 17:18:59 +0000</pubDate>
      <link>https://dev.to/sylvain_tiassou_61317f8f2/building-a-safe-by-design-http-telemetry-crate-in-rust-2kkb</link>
      <guid>https://dev.to/sylvain_tiassou_61317f8f2/building-a-safe-by-design-http-telemetry-crate-in-rust-2kkb</guid>
      <description>&lt;p&gt;Incidents are easier to investigate when you can see what happened inside your HTTP service: which route failed, how long it took, and what the request looked like.&lt;/p&gt;

&lt;p&gt;But logging request data can create new problems. Passwords and tokens may end up in logs. Large payloads can consume memory. And if telemetry export waits on a slow or unavailable backend, it can affect the request path.&lt;/p&gt;

&lt;p&gt;To address these tradeoffs, I built safe-http-telemetry, an open-source Rust crate for Axum and Tower applications.&lt;/p&gt;

&lt;p&gt;Its design goal is to make HTTP telemetry useful while keeping capture, resource use, and export behavior under the application’s control.&lt;br&gt;
Three design priorities&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Redact sensitive data before queueing
When an application captures request data, it needs to consider credentials such as passwords, bearer tokens, and API keys.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;safe-http-telemetry applies capture limits and redaction before events enter the export queue. It supports configured sensitive-field matching in query parameters, headers, and supported structured body formats. JSON objects are traversed recursively, with limits on depth, visited nodes, and string size.&lt;/p&gt;

&lt;p&gt;Body capture is optional. It requires the body-capture feature and a route configured for the Detailed profile. Applications can also add field names specific to their own domain.&lt;/p&gt;

&lt;p&gt;Redaction is a safeguard, not a guarantee that every secret will be identified. I recommend starting with the Minimal profile, enabling richer capture only on reviewed routes, and limiting access to the telemetry backend.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep the request path independent from Loki
The middleware submits events to a bounded queue without waiting for a network export. Background workers can consume and batch events for asynchronous delivery to Grafana Loki.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the queue fills up, the default DropNewest policy rejects the incoming event and updates operational counters. This keeps queue memory bounded and avoids waiting for Loki to become available. The application can monitor these counters and configure limits to suit its workload.&lt;/p&gt;

&lt;p&gt;The event flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP request
     │
     ▼
Axum / Tower middleware
     │
     ▼
Route policy → bounded capture → redaction
     │
     ▼
Bounded event queue ── full? ──► drop newest + update counters
     │
     ▼
Background exporter workers
     │
     ▼
Grafana Loki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue and exporter have separate responsibilities: the middleware prepares events, while the consumer handles delivery and shutdown.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make geolocation an explicit local option
For applications that need it, the optional geolocation feature can look up country information using a local MMDB database. The database is supplied separately, loaded during setup, and is not downloaded by the crate. Lookups do not call an external geolocation API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The cache has configurable capacity and time-to-live limits. By default, the event includes country code and country name; the application can choose other supported fields. Geolocation depends on resolving the client IP correctly, so forwarded headers should only be trusted from configured proxy networks.&lt;br&gt;
A small Axum integration surface&lt;br&gt;
After creating a bounded queue and route policies, attach the layer to your router:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="n"&gt;telemetry_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;axum_telemetry_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MiddlewareConfig&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/hello/{name}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;telemetry_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Axum, register routes before applying the layer so the middleware can record normalized route templates. The crate leaves server setup, queue consumption, and shutdown sequencing to the application.&lt;br&gt;
What the benchmarks show&lt;br&gt;
I used Criterion to measure middleware overhead with tower::ServiceExt::oneshot. The recorded run compared a service without telemetry to three capture profiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Baseline: 2.38 µs&lt;/li&gt;
&lt;li&gt;Minimal: 27.31 µs&lt;/li&gt;
&lt;li&gt;Standard: 60.16 µs&lt;/li&gt;
&lt;li&gt;Detailed: 71.58 µs
These are estimates from a documented run on one machine, not universal performance guarantees. The benchmark does not measure network throughput, tail latency under load, or sustained exporter outages. The geolocation case in that run did not supply a client IP, so it did not measure an actual database lookup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a real service, benchmark with representative payloads, concurrency, and capture policies.&lt;br&gt;
Testing malformed and unexpected input&lt;br&gt;
The repository includes property-based tests with proptest for configuration, policy resolution, and queue capacity. It also includes cargo-fuzz targets for query, header, and JSON redaction inputs.&lt;/p&gt;

&lt;p&gt;These checks help exercise boundary conditions and malformed data. They complement application-specific testing, especially when adding custom sensitive field names or enabling detailed body capture.&lt;br&gt;
What I learned&lt;br&gt;
Building this crate reinforced that observability is not just about collecting more logs. It also involves data minimization, backpressure, resource limits, and graceful behavior when a backend is unavailable.&lt;/p&gt;

&lt;p&gt;safe-http-telemetry is available on crates.io. If you build with Axum or Tower, I’d welcome feedback on the integration, documentation, performance, and any edge cases you find.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crate: &lt;a href="//crates.io/crates/safe-http-telemetry"&gt;crates.io/crates/safe-http-telemetry&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repository: &lt;a href="//github.com/sylvainTIASSOU/safe-http-telemetry"&gt;github.com/sylvainTIASSOU/safe-http-telemetry&lt;/a&gt;
Bug reports, feature suggestions, and contributions are very welcome. 🦀&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>opensource</category>
      <category>rust</category>
      <category>security</category>
    </item>
  </channel>
</rss>
