<?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: Farhan Munir</title>
    <description>The latest articles on DEV Community by Farhan Munir (@munirfarhan).</description>
    <link>https://dev.to/munirfarhan</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%2F3833974%2Fd6f31945-fbf3-430a-aca8-9937f9230037.jpg</url>
      <title>DEV Community: Farhan Munir</title>
      <link>https://dev.to/munirfarhan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/munirfarhan"/>
    <language>en</language>
    <item>
      <title>Configurable Video Transition Duration in Reel Quick</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Sun, 26 Jul 2026 09:38:03 +0000</pubDate>
      <link>https://dev.to/munirfarhan/configurable-video-transition-duration-in-reel-quick-5gpj</link>
      <guid>https://dev.to/munirfarhan/configurable-video-transition-duration-in-reel-quick-5gpj</guid>
      <description>&lt;p&gt;Video transitions are one of those details that quietly shape the feel of an edit.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://github.com/ronin1770/reel-quick/issues/13" rel="noopener noreferrer"&gt;Reel Quick issue #13&lt;/a&gt;, the goal was simple: let users control how long a scene transition lasts instead of forcing a fixed value.&lt;/p&gt;

&lt;p&gt;Issue URL: &lt;a href="https://github.com/ronin1770/reel-quick/issues/13" rel="noopener noreferrer"&gt;https://github.com/ronin1770/reel-quick/issues/13&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;The app already supported transition effects between scenes, but the duration was fixed.&lt;/p&gt;

&lt;p&gt;That meant creators could choose &lt;em&gt;what&lt;/em&gt; transition to use, but not &lt;em&gt;how long&lt;/em&gt; it should run.&lt;/p&gt;

&lt;p&gt;For short-form video, that matters a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fast transitions create a snappier pace&lt;/li&gt;
&lt;li&gt;longer transitions feel smoother or more cinematic&lt;/li&gt;
&lt;li&gt;some edits need no transition at all&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The feature
&lt;/h2&gt;

&lt;p&gt;The new behavior adds a configurable transition duration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;minimum: &lt;code&gt;0.0&lt;/code&gt; seconds&lt;/li&gt;
&lt;li&gt;maximum: &lt;code&gt;4.0&lt;/code&gt; seconds&lt;/li&gt;
&lt;li&gt;step: &lt;code&gt;0.5&lt;/code&gt; seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A slider in the frontend lets the user choose the duration, and that value is sent to the backend for FFmpeg video generation.&lt;/p&gt;

&lt;p&gt;If the value is &lt;code&gt;0.0&lt;/code&gt;, transitions are disabled entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The FFmpeg math
&lt;/h2&gt;

&lt;p&gt;When two clips are joined with a transition, the transition overlaps the end of the first clip and the start of the second clip.&lt;/p&gt;

&lt;p&gt;So the final duration is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;final length = clip 1 + clip 2 - transition duration&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clip 1 = &lt;code&gt;7&lt;/code&gt; seconds&lt;/li&gt;
&lt;li&gt;Clip 2 = &lt;code&gt;8&lt;/code&gt; seconds&lt;/li&gt;
&lt;li&gt;Transition duration = &lt;code&gt;4&lt;/code&gt; seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Math:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;7 + 8 - 4 = 11 seconds&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Final video length: &lt;code&gt;11 seconds&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 2
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clip 1 = &lt;code&gt;7&lt;/code&gt; seconds&lt;/li&gt;
&lt;li&gt;Clip 2 = &lt;code&gt;8&lt;/code&gt; seconds&lt;/li&gt;
&lt;li&gt;Transition duration = &lt;code&gt;0.5&lt;/code&gt; seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Math:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;7 + 8 - 0.5 = 14.5 seconds&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Final video length: &lt;code&gt;14.5 seconds&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why validation matters
&lt;/h2&gt;

&lt;p&gt;This feature also needs guardrails.&lt;/p&gt;

&lt;p&gt;The backend validates that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the duration is between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the duration is a multiple of &lt;code&gt;0.5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;clips are long enough for the selected transition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is important. A &lt;code&gt;4&lt;/code&gt; second transition cannot work safely if a clip itself is only &lt;code&gt;3&lt;/code&gt; seconds long.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation notes
&lt;/h2&gt;

&lt;p&gt;The implementation touches both frontend and backend:&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;add a transition duration slider&lt;/li&gt;
&lt;li&gt;show the selected value beside it&lt;/li&gt;
&lt;li&gt;send &lt;code&gt;transition_duration&lt;/code&gt; in the video creation request&lt;/li&gt;
&lt;li&gt;show inline validation errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;accept &lt;code&gt;transition_duration&lt;/code&gt; in the API&lt;/li&gt;
&lt;li&gt;validate the range and step&lt;/li&gt;
&lt;li&gt;preserve the default behavior when no value is supplied&lt;/li&gt;
&lt;li&gt;pass the value into FFmpeg transition generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The key idea
&lt;/h2&gt;

&lt;p&gt;The transition does not add extra time to the video.&lt;/p&gt;

&lt;p&gt;It overlaps clips.&lt;/p&gt;

&lt;p&gt;That is the core reason the final duration becomes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sum of clips - overlap&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;n&lt;/code&gt; clips, the total duration becomes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sum(all clip durations) - sum(all transition overlaps)&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Open source note
&lt;/h2&gt;

&lt;p&gt;Small editing controls like this can have a big impact on creative flexibility.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of feature that makes open source video tools more useful in real workflows: not flashy, just practical and user-driven.&lt;/p&gt;

&lt;p&gt;If you want to follow the discussion or implementation details, see the issue here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ronin1770/reel-quick/issues/13" rel="noopener noreferrer"&gt;https://github.com/ronin1770/reel-quick/issues/13&lt;/a&gt;&lt;/p&gt;

</description>
      <category>instagram</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>flask</category>
    </item>
    <item>
      <title>Implementing HTTP 429 Retry-After Handling in Heka Insights Agent</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Sat, 25 Jul 2026 10:34:29 +0000</pubDate>
      <link>https://dev.to/munirfarhan/implementing-http-429-retry-after-handling-in-heka-insights-agent-5d30</link>
      <guid>https://dev.to/munirfarhan/implementing-http-429-retry-after-handling-in-heka-insights-agent-5d30</guid>
      <description>&lt;p&gt;We opened a focused reliability issue in the Heka Insights Agent to improve how the OTLP HTTP exporter behaves under backend rate limiting.&lt;/p&gt;

&lt;p&gt;Issue URL: &lt;a href="https://github.com/ronin1770/heka-insights-agent/issues/22" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent/issues/22&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is simple: if an ingestion gateway returns &lt;code&gt;429 Too Many Requests&lt;/code&gt;, the agent should not immediately keep retrying on a short generic backoff loop until all attempts are exhausted.&lt;/p&gt;

&lt;p&gt;If the server says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;429 Too Many Requests
Retry-After: 20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the agent should respect that instruction, wait, and retry the same metrics batch at the correct time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;In telemetry pipelines, rate limiting is normal. Gateways protect themselves, vendors enforce quotas, and burst traffic happens.&lt;/p&gt;

&lt;p&gt;What matters is how the agent behaves when that happens.&lt;/p&gt;

&lt;p&gt;A weak retry strategy looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;request fails with &lt;code&gt;429&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;exporter retries too quickly&lt;/li&gt;
&lt;li&gt;all configured attempts are consumed before the rate-limit window resets&lt;/li&gt;
&lt;li&gt;the batch fails even though the backend gave a valid recovery signal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not just inefficient. It also creates noisy logs, unnecessary traffic, and lower delivery reliability.&lt;/p&gt;

&lt;p&gt;For an agent that is expected to stay running continuously, this is the wrong operational behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal of Issue #22
&lt;/h2&gt;

&lt;p&gt;Issue #22 defines a more correct path for &lt;code&gt;429 Too Many Requests&lt;/code&gt; handling in the OTLP HTTP exporter.&lt;/p&gt;

&lt;p&gt;The required behavior is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;detect &lt;code&gt;429&lt;/code&gt; explicitly instead of treating it like a generic transient HTTP error&lt;/li&gt;
&lt;li&gt;read the &lt;code&gt;Retry-After&lt;/code&gt; header case-insensitively&lt;/li&gt;
&lt;li&gt;support integer-second delay values&lt;/li&gt;
&lt;li&gt;use a default delay when the header is missing or invalid&lt;/li&gt;
&lt;li&gt;cap excessive values with configuration&lt;/li&gt;
&lt;li&gt;retry the same OTLP payload&lt;/li&gt;
&lt;li&gt;reuse the same idempotency key&lt;/li&gt;
&lt;li&gt;avoid stacking exponential backoff on top of server-provided delay&lt;/li&gt;
&lt;li&gt;keep the main agent process and collectors running&lt;/li&gt;
&lt;li&gt;add logging and timing instrumentation around the retry path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a narrow but important reliability improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Design Choice
&lt;/h2&gt;

&lt;p&gt;The most important part of the issue is not just "sleep and retry."&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;retrying the same batch with the same idempotency key&lt;/strong&gt; after honoring the delay requested by the server.&lt;/p&gt;

&lt;p&gt;That protects correctness in a few ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the exporter does not replace the pending batch with newer metrics&lt;/li&gt;
&lt;li&gt;retry semantics stay tied to the original request&lt;/li&gt;
&lt;li&gt;the backend sees the same logical delivery attempt after the rate-limit window&lt;/li&gt;
&lt;li&gt;clients do not accidentally create duplicate semantics by regenerating request identity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially important for observability delivery paths, where retries need to be operationally safe, not just convenient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration Rules
&lt;/h2&gt;

&lt;p&gt;The issue introduces explicit control for Retry-After behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OTLP_RETRY_AFTER_DEFAULT_SECONDS=5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OTLP_RETRY_AFTER_MAX_SECONDS=300&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OTLP_MAX_EXPORT_ATTEMPTS=5&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives the exporter deterministic behavior across common cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing header -&amp;gt; use default&lt;/li&gt;
&lt;li&gt;empty header -&amp;gt; use default&lt;/li&gt;
&lt;li&gt;invalid value -&amp;gt; use default&lt;/li&gt;
&lt;li&gt;negative value -&amp;gt; use default&lt;/li&gt;
&lt;li&gt;zero -&amp;gt; retry without additional delay&lt;/li&gt;
&lt;li&gt;value above max -&amp;gt; cap it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the kind of behavior that operators can reason about quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async Sleep Matters
&lt;/h2&gt;

&lt;p&gt;One of the stronger requirements in the issue is that the wait must be asynchronous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retry_after_seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That detail matters because the agent should continue running normally while one export batch is waiting for its retry window.&lt;/p&gt;

&lt;p&gt;The wait should not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;block the event loop&lt;/li&gt;
&lt;li&gt;freeze collectors&lt;/li&gt;
&lt;li&gt;terminate the process&lt;/li&gt;
&lt;li&gt;force a broad retry redesign for unrelated HTTP failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the scope disciplined while still improving real runtime behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging and Timing
&lt;/h2&gt;

&lt;p&gt;The issue also calls for better observability around exporter retries themselves.&lt;/p&gt;

&lt;p&gt;That includes logging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;endpoint&lt;/li&gt;
&lt;li&gt;HTTP status&lt;/li&gt;
&lt;li&gt;current attempt&lt;/li&gt;
&lt;li&gt;maximum attempts&lt;/li&gt;
&lt;li&gt;parsed Retry-After value&lt;/li&gt;
&lt;li&gt;applied delay&lt;/li&gt;
&lt;li&gt;whether defaulting or capping occurred&lt;/li&gt;
&lt;li&gt;masked idempotency-key reference&lt;/li&gt;
&lt;li&gt;retry outcome&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also asks for timing data such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;retry_after_parse_ms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;retry_after_sleep_seconds&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;retry_request_ms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;total_batch_export_ms&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is important because retry logic without timing visibility becomes difficult to debug in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Scope
&lt;/h2&gt;

&lt;p&gt;Issue #22 is also explicit about testing expectations.&lt;/p&gt;

&lt;p&gt;The test coverage should verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;header parsing for valid and invalid cases&lt;/li&gt;
&lt;li&gt;case-insensitive header handling&lt;/li&gt;
&lt;li&gt;same payload reuse on retry&lt;/li&gt;
&lt;li&gt;same idempotency key reuse on retry&lt;/li&gt;
&lt;li&gt;correct attempt accounting&lt;/li&gt;
&lt;li&gt;no extra exponential backoff layered onto Retry-After&lt;/li&gt;
&lt;li&gt;successful retry exit behavior&lt;/li&gt;
&lt;li&gt;max-attempt failure without crashing the agent&lt;/li&gt;
&lt;li&gt;clean shutdown during the wait&lt;/li&gt;
&lt;li&gt;collector continuity while the exporter is waiting&lt;/li&gt;
&lt;li&gt;no logging of secrets or raw OTLP payloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a clear integration expectation: return &lt;code&gt;429&lt;/code&gt;, wait the correct amount of time, retry the same batch, then succeed and exit the retry loop cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Like This Issue
&lt;/h2&gt;

&lt;p&gt;This is the kind of issue that improves a system in a practical way.&lt;/p&gt;

&lt;p&gt;It does not try to redesign all retry behavior in one pass. It focuses on one real failure mode, defines the expected runtime behavior precisely, and forces the implementation to think about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;correctness&lt;/li&gt;
&lt;li&gt;idempotency&lt;/li&gt;
&lt;li&gt;async behavior&lt;/li&gt;
&lt;li&gt;operational visibility&lt;/li&gt;
&lt;li&gt;bounded configuration&lt;/li&gt;
&lt;li&gt;testability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a good pattern for infrastructure work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the Issue
&lt;/h2&gt;

&lt;p&gt;If you want the full requirement set and acceptance criteria, the issue is here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ronin1770/heka-insights-agent/issues/22" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent/issues/22&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're interested in Linux telemetry agents, OTLP delivery behavior, or exporter reliability work, the repository is here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>testing</category>
      <category>opentelemetry</category>
    </item>
    <item>
      <title>Reel Quick: Added Video Transition Effects and a Theme Selector</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Wed, 15 Jul 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/munirfarhan/reel-quick-added-video-transition-effects-and-a-theme-selector-46mp</link>
      <guid>https://dev.to/munirfarhan/reel-quick-added-video-transition-effects-and-a-theme-selector-46mp</guid>
      <description>&lt;h1&gt;
  
  
  Reel Quick: Added Video Transition Effects and a Theme Selector
&lt;/h1&gt;

&lt;p&gt;I’ve been improving &lt;strong&gt;Reel Quick&lt;/strong&gt;, an open-source Instagram reels generator built with &lt;strong&gt;FastAPI, Next.js, and ARQ&lt;/strong&gt;. The latest update adds two practical frontend/video workflow improvements: &lt;strong&gt;video transition effects&lt;/strong&gt; and a &lt;strong&gt;theme selector&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The transition work makes reel stitching feel more polished by adding support for scene transition effects between clips. For this release, I also added sample input/output media so the behavior is easy to inspect directly. On the UI side, Reel Quick now supports a &lt;strong&gt;theme selector&lt;/strong&gt; with multiple appearance modes, making the interface more flexible for different working environments and user preferences.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was added
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Video transition effects&lt;/li&gt;
&lt;li&gt;Sample transition input clips&lt;/li&gt;
&lt;li&gt;Sample output video showing a circle transition&lt;/li&gt;
&lt;li&gt;Theme selector demo output video&lt;/li&gt;
&lt;li&gt;Updated project documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;For reel creation workflows, transitions improve the final viewing experience without forcing extra manual editing outside the tool. The theme selector improves usability for longer editing sessions and makes the app feel more production-ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/ronin1770/reel-quick" rel="noopener noreferrer"&gt;https://github.com/ronin1770/reel-quick&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Issue: &lt;a href="https://github.com/ronin1770/reel-quick/issues/11" rel="noopener noreferrer"&gt;https://github.com/ronin1770/reel-quick/issues/11&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo assets
&lt;/h2&gt;

&lt;p&gt;Inside the repo docs folder you can find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transition input clips&lt;/li&gt;
&lt;li&gt;Transition output example&lt;/li&gt;
&lt;li&gt;Theme selector demo video&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to follow the implementation discussion and scope, check the linked issue above.&lt;/p&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>opensource</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Adding RPM Packaging for CentOS 9 in Heka Insights</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Sun, 12 Jul 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/munirfarhan/adding-rpm-packaging-for-centos-9-in-heka-insights-3cj3</link>
      <guid>https://dev.to/munirfarhan/adding-rpm-packaging-for-centos-9-in-heka-insights-3cj3</guid>
      <description>&lt;p&gt;Heka Insights Agent now includes a dedicated RPM packaging workflow for CentOS Stream 9 and other Enterprise Linux 9-compatible distributions.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://sl1nk.com/dpi1j6p" rel="noopener noreferrer"&gt;https://sl1nk.com/dpi1j6p&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project already supported packaged installation on Debian-based systems, but RPM-based environments need their own build format, package metadata, lifecycle scripts, and installation workflow.&lt;/p&gt;

&lt;p&gt;This release adds that missing path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported RPM-based distributions
&lt;/h2&gt;

&lt;p&gt;The new packaging flow targets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CentOS Stream 9&lt;/li&gt;
&lt;li&gt;Red Hat Enterprise Linux 9&lt;/li&gt;
&lt;li&gt;Rocky Linux 9&lt;/li&gt;
&lt;li&gt;AlmaLinux 9&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of attempting to reuse a Debian &lt;code&gt;.deb&lt;/code&gt; package, operators can now build and install a native &lt;code&gt;.rpm&lt;/code&gt; artifact using the standard &lt;code&gt;dnf&lt;/code&gt; and &lt;code&gt;rpm&lt;/code&gt; ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was added
&lt;/h2&gt;

&lt;p&gt;The repository now includes a dedicated RPM packaging structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;packaging/rpm/build_rpm.sh
packaging/rpm/heka-insights-agent.spec
packaging/rpm/heka-insights-agent.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The build script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates the standalone agent binary with PyInstaller.&lt;/li&gt;
&lt;li&gt;Prepares the RPM build directories.&lt;/li&gt;
&lt;li&gt;Copies the binary, systemd unit, documentation, and configuration example.&lt;/li&gt;
&lt;li&gt;Runs &lt;code&gt;rpmbuild&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Generates the final RPM and SHA-256 checksum.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The generated artifact follows the standard EL9 naming format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heka-insights-agent-0.1.0-1.el9.x86_64.rpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why native RPM packaging matters
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;.deb&lt;/code&gt; package is not a CentOS release artifact.&lt;/p&gt;

&lt;p&gt;Debian and Enterprise Linux distributions use different package formats, package managers, dependency metadata, and installation lifecycle hooks.&lt;/p&gt;

&lt;p&gt;CentOS 9 and related systems expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RPM package metadata&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dnf&lt;/code&gt;-compatible dependency handling&lt;/li&gt;
&lt;li&gt;RPM installation and removal scriptlets&lt;/li&gt;
&lt;li&gt;EL9-compatible binaries&lt;/li&gt;
&lt;li&gt;systemd integration&lt;/li&gt;
&lt;li&gt;Enterprise Linux filesystem conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building the agent directly on an EL9 system also reduces compatibility risks with native libraries such as glibc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistent runtime model
&lt;/h2&gt;

&lt;p&gt;The packaging format changes, but the agent’s runtime model remains consistent.&lt;/p&gt;

&lt;p&gt;The RPM installs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/local/bin/heka-insights-agent
/usr/lib/systemd/system/heka-insights-agent.service
/etc/heka-insights-agent/
/var/log/heka-insights-agent/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration is completed through the setup command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; /usr/local/bin/heka-insights-agent setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service can then be enabled and started with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; heka-insights-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Service output is available through the systemd journal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; heka-insights-agent &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package also creates the agent service account and prepares the required configuration and log directories with restricted permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaner release artifacts
&lt;/h2&gt;

&lt;p&gt;Platform-specific output is now separated inside &lt;code&gt;dist/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dist/ubuntu/
dist/centos9/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps Debian and RPM artifacts clearly separated and makes multi-platform release automation easier to maintain.&lt;/p&gt;

&lt;p&gt;A release can now provide artifacts such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heka-insights-agent_0.1.0_amd64.deb
heka-insights-agent-0.1.0-1.el9.x86_64.rpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installation on CentOS 9
&lt;/h2&gt;

&lt;p&gt;The generated RPM can be installed using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ./heka-insights-agent-0.1.0-1.el9.x86_64.rpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; /usr/local/bin/heka-insights-agent setup
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; heka-insights-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service can be verified with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status heka-insights-agent &lt;span class="nt"&gt;--no-pager&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A practical release improvement
&lt;/h2&gt;

&lt;p&gt;This is not a change to the telemetry engine itself, but it is an important operational improvement.&lt;/p&gt;

&lt;p&gt;Teams using CentOS Stream, RHEL, Rocky Linux, or AlmaLinux can now evaluate and deploy Heka Insights Agent using a package format that matches their infrastructure.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer manual installation steps&lt;/li&gt;
&lt;li&gt;clearer release documentation&lt;/li&gt;
&lt;li&gt;native package management&lt;/li&gt;
&lt;li&gt;easier upgrades and removals&lt;/li&gt;
&lt;li&gt;more consistent production rollouts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Review the source, packaging scripts, and release documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sl1nk.com/dpi1j6p" rel="noopener noreferrer"&gt;https://sl1nk.com/dpi1j6p&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>centos</category>
      <category>telemetry</category>
    </item>
    <item>
      <title>I Added Scene Transitions to Reel Quick with FastAPI, Next.js, and FFmpeg</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Sat, 11 Jul 2026 06:13:26 +0000</pubDate>
      <link>https://dev.to/munirfarhan/i-added-scene-transitions-to-reel-quick-with-fastapi-nextjs-and-ffmpeg-33a3</link>
      <guid>https://dev.to/munirfarhan/i-added-scene-transitions-to-reel-quick-with-fastapi-nextjs-and-ffmpeg-33a3</guid>
      <description>&lt;p&gt;Building reels by stitching short clips together works, but hard cuts can make the final video feel rough. I wanted Reel Quick to produce something smoother without forcing creators to leave the app and finish the job in a separate editor.&lt;/p&gt;

&lt;p&gt;This update adds scene transitions to Reel Quick. When creating a reel, you can now choose a transition and have it applied automatically at every scene boundary. That keeps the workflow simple while making the final output feel more polished.&lt;/p&gt;

&lt;p&gt;On the backend, I added a transition catalog for supported FFmpeg xfade effects, including fade, dissolve, fadeblack, fadewhite, wipeleft, wiperight, slideleft, slideright, circleopen, and circleclose. The API validates the selected transition, stores it with the video, and exposes transition records so the frontend can load only active options.&lt;/p&gt;

&lt;p&gt;On the frontend, the create-video flow now fetches available transitions and lets the user pick one before the job is queued. From there, the worker passes that choice into the render pipeline, and FFmpeg applies the selected transition between trimmed clips during output generation.&lt;/p&gt;

&lt;p&gt;One detail that matters: this feature depends on FFmpeg support for the xfade filter. If the local FFmpeg build supports it, Reel Quick can now turn plain stitched clips into cleaner, more watchable reels with no extra editing step.&lt;/p&gt;

&lt;p&gt;This is the kind of update I like most: small on the surface, but meaningful in the final result. It improves creator output, keeps the API workflow clean, and moves Reel Quick closer to being a practical open source reel-production tool.&lt;/p&gt;

&lt;p&gt;Output video: &lt;a href="https://drive.google.com/file/d/1HqOj9ZctlApq2AO2ylS16YXYhy6gu7AO/view?usp=sharing" rel="noopener noreferrer"&gt;https://drive.google.com/file/d/1HqOj9ZctlApq2AO2ylS16YXYhy6gu7AO/view?usp=sharing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Issue: &lt;a href="https://github.com/ronin1770/reel-quick/issues/1" rel="noopener noreferrer"&gt;https://github.com/ronin1770/reel-quick/issues/1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/ronin1770/reel-quick" rel="noopener noreferrer"&gt;https://github.com/ronin1770/reel-quick&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>ffmpeg</category>
      <category>python</category>
    </item>
    <item>
      <title>Feature Request: Theme Switching for Reel-Quick</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Tue, 07 Jul 2026 10:56:59 +0000</pubDate>
      <link>https://dev.to/munirfarhan/feature-request-theme-switching-for-reel-quick-2oim</link>
      <guid>https://dev.to/munirfarhan/feature-request-theme-switching-for-reel-quick-2oim</guid>
      <description>&lt;p&gt;I have opened a feature request to add frontend theme support to Reel-Quick.&lt;/p&gt;

&lt;p&gt;The proposed feature would allow users to select between Light, Dark, and System-default themes. The selected preference should persist across sessions and apply consistently throughout the application.&lt;/p&gt;

&lt;p&gt;Because Reel-Quick is built with Next.js, this could be implemented using a theme provider such as next-themes, together with CSS variables, Tailwind dark-mode utilities, or the project’s existing styling approach.&lt;/p&gt;

&lt;p&gt;Theme support would improve accessibility, reduce visual fatigue in low-light environments, and make the platform more adaptable for individual users and future team deployments.&lt;/p&gt;

&lt;p&gt;The initial scope can remain simple: Light, Dark, and System modes. Later enhancements could include accent colors, high-contrast mode, compact layouts, or organization-level branding.&lt;/p&gt;

&lt;p&gt;View, discuss, or contribute to the feature request here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ronin1770/reel-quick/issues/11" rel="noopener noreferrer"&gt;https://github.com/ronin1770/reel-quick/issues/11&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>Introducing Heka Insights Agent v0.1.0: Our First Release</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Wed, 01 Jul 2026 18:08:25 +0000</pubDate>
      <link>https://dev.to/munirfarhan/introducing-heka-insights-agent-v010-our-first-release-4k06</link>
      <guid>https://dev.to/munirfarhan/introducing-heka-insights-agent-v010-our-first-release-4k06</guid>
      <description>&lt;p&gt;We are shipping the &lt;strong&gt;first release&lt;/strong&gt; of Heka Insights Agent.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;ronin1770/heka-insights-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Heka Insights Agent is a lightweight Linux telemetry agent focused on a simple goal: collect host-level signals, normalize them into a consistent format, and make delivery flexible enough for different observability backends.&lt;/p&gt;

&lt;p&gt;For this first release, we wanted to establish a solid base instead of trying to do everything at once. That means a working runtime, clear configuration, multiple exporter options, and a packaging story that makes installation easier on real Linux systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Heka Insights Agent Is
&lt;/h2&gt;

&lt;p&gt;At its core, Heka Insights Agent is designed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collect essential Linux host telemetry&lt;/li&gt;
&lt;li&gt;normalize metrics into a consistent internal model&lt;/li&gt;
&lt;li&gt;keep collection separate from delivery&lt;/li&gt;
&lt;li&gt;support multiple backend paths without changing collectors&lt;/li&gt;
&lt;li&gt;stay lightweight enough for continuous runtime use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That separation is important. It means the agent is not tightly locked to one vendor from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Ships in v0.1.0
&lt;/h2&gt;

&lt;p&gt;This first release includes several important pieces.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Linux host telemetry collection
&lt;/h3&gt;

&lt;p&gt;The project collects core machine-level signals such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU usage&lt;/li&gt;
&lt;li&gt;memory usage&lt;/li&gt;
&lt;li&gt;disk I/O&lt;/li&gt;
&lt;li&gt;runtime health-oriented metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to keep the foundation practical and extensible.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Multiple exporter paths
&lt;/h3&gt;

&lt;p&gt;This release supports a small but meaningful set of delivery modes through &lt;code&gt;EXPORTER_TYPE&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;console&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;otlp_http&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;datadog_otlp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;datadog_native&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;newrelic_otlp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives teams a path to start locally, use standard OTLP HTTP delivery, or integrate with Datadog and New Relic using repo-supported configuration flows.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Strict runtime configuration behavior
&lt;/h3&gt;

&lt;p&gt;One of the priorities in this release is predictable startup behavior.&lt;/p&gt;

&lt;p&gt;Instead of silently accepting bad configuration, the runtime validates required settings and fails fast when critical exporter values are missing or malformed. That matters a lot for agents that are expected to run unattended.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Debian package build and install flow
&lt;/h3&gt;

&lt;p&gt;This release also includes a Debian packaging path for Ubuntu &lt;code&gt;amd64&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The package flow covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a bundled executable under &lt;code&gt;/usr/local/bin/heka-insights-agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a systemd service unit&lt;/li&gt;
&lt;li&gt;packaged runtime config under &lt;code&gt;/etc/heka-insights-agent/.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;log output under &lt;code&gt;/var/log/heka-insights-agent/agent.log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;an interactive setup path for first-time installation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a meaningful step forward compared with a repo-only Python workflow, because it gives users a clearer route for installing the agent as a managed service.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Interactive setup flow
&lt;/h3&gt;

&lt;p&gt;The packaged runtime includes a setup mode so installation is not just "copy files and figure it out yourself."&lt;/p&gt;

&lt;p&gt;The setup flow is meant to help with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;selecting exporter mode&lt;/li&gt;
&lt;li&gt;capturing required environment values&lt;/li&gt;
&lt;li&gt;writing packaged runtime configuration&lt;/li&gt;
&lt;li&gt;enabling and starting the service on success&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the first release much closer to something an operator can actually install and use.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Docs and test coverage around the exporter paths
&lt;/h3&gt;

&lt;p&gt;We also shipped supporting documentation and test coverage for the exporter/runtime surface, including milestone-specific integration coverage for the Datadog and New Relic paths.&lt;/p&gt;

&lt;p&gt;That does not mean the project is feature-complete. It means the base is being treated seriously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation Direction
&lt;/h2&gt;

&lt;p&gt;For release users, the install direction is now straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; heka-insights-agent_&amp;lt;version&amp;gt;_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If setup is interrupted, it can be resumed with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; /usr/local/bin/heka-insights-agent setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This first release is intentionally Linux-focused and packaging-aware from the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We’re Starting Here
&lt;/h2&gt;

&lt;p&gt;There are already many observability tools in the market, but there is still room for agents that are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simpler to understand&lt;/li&gt;
&lt;li&gt;easier to extend&lt;/li&gt;
&lt;li&gt;less coupled to a single backend&lt;/li&gt;
&lt;li&gt;easier to package and operate on Linux hosts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first release is about getting those fundamentals in place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collection&lt;/li&gt;
&lt;li&gt;normalization&lt;/li&gt;
&lt;li&gt;delivery options&lt;/li&gt;
&lt;li&gt;installability&lt;/li&gt;
&lt;li&gt;operational clarity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Open Source Repo
&lt;/h2&gt;

&lt;p&gt;If you want to inspect the code, follow the release progress, or contribute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;ronin1770/heka-insights-agent&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;From here, the focus is to keep improving the agent in practical ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deeper collector coverage&lt;/li&gt;
&lt;li&gt;stronger runtime hardening&lt;/li&gt;
&lt;li&gt;broader integration coverage&lt;/li&gt;
&lt;li&gt;more production-oriented examples&lt;/li&gt;
&lt;li&gt;continued packaging and rollout improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is that the first release is no longer just an idea. There is now a concrete repo, a real runtime, documented exporter behavior, and a packaged install path to build on.&lt;/p&gt;

</description>
      <category>python</category>
      <category>linux</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Heka-Insights-Agent: Milestone 6 Complete: Datadog OTLP + Native Integration Paths</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Sun, 17 May 2026 06:04:48 +0000</pubDate>
      <link>https://dev.to/munirfarhan/heka-insights-agent-milestone-6-complete-datadog-otlp-native-integration-paths-4144</link>
      <guid>https://dev.to/munirfarhan/heka-insights-agent-milestone-6-complete-datadog-otlp-native-integration-paths-4144</guid>
      <description>&lt;p&gt;Milestone 6 is complete for the Heka Insights Agent.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this milestone, we implemented &lt;strong&gt;two Datadog-compatible delivery paths&lt;/strong&gt; so teams can choose what fits their needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Datadog OTLP preset mode&lt;/strong&gt; (&lt;code&gt;EXPORTER_TYPE=datadog_otlp&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Datadog native API mode&lt;/strong&gt; (&lt;code&gt;EXPORTER_TYPE=datadog_native&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Milestone 6 Goal
&lt;/h2&gt;

&lt;p&gt;Provide Datadog integration through both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OTLP-based delivery for portability&lt;/li&gt;
&lt;li&gt;Datadog-native delivery for backend-specific control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In common terms: this means your agent can now send metrics to Datadog in either a standards-oriented way (OTLP) or a Datadog-specific way (native API), without changing your collectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Implemented
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Datadog OTLP preset mode (&lt;code&gt;datadog_otlp&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;We added a Datadog preset resolver that derives endpoint + auth headers from Datadog config.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;endpoint is derived from site: &lt;code&gt;https://otlp.&amp;lt;DATADOG_SITE&amp;gt;/v1/metrics&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;auth header is injected: &lt;code&gt;dd-api-key: &amp;lt;DATADOG_API_KEY&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;optional Datadog hostname/tags are mapped into resource attributes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Datadog native exporter (&lt;code&gt;datadog_native&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;We implemented a native Datadog metrics exporter for &lt;code&gt;POST /api/v1/series&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;endpoint is derived from site: &lt;code&gt;https://api.&amp;lt;DATADOG_SITE&amp;gt;/api/v1/series&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;canonical &lt;code&gt;gauge&lt;/code&gt; -&amp;gt; Datadog &lt;code&gt;gauge&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;canonical &lt;code&gt;counter&lt;/code&gt; -&amp;gt; Datadog &lt;code&gt;count&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timestamp_unix_ms&lt;/code&gt; -&amp;gt; Unix seconds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;count.interval&lt;/code&gt; is derived from &lt;code&gt;CPU_POLL_INTERVAL_SECONDS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Validation hardening (M6-3)
&lt;/h3&gt;

&lt;p&gt;We fail fast on invalid/missing Datadog config:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DATADOG_SITE&lt;/code&gt; must be an allowed full domain&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DATADOG_API_KEY&lt;/code&gt; must be non-empty&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DATADOG_TAGS&lt;/code&gt; must be strict &lt;code&gt;key:value&lt;/code&gt; format&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Deterministic mapping rules (M6-4)
&lt;/h3&gt;

&lt;p&gt;We made mapping predictable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DATADOG_HOSTNAME&lt;/code&gt; overrides label-derived host&lt;/li&gt;
&lt;li&gt;tag conflicts are deterministic (&lt;code&gt;DATADOG_TAGS&lt;/code&gt; override label tags by key)&lt;/li&gt;
&lt;li&gt;metric prefixing is idempotent (won't double-prefix)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. OTLP vs native comparison docs (M6-5)
&lt;/h3&gt;

&lt;p&gt;We added side-by-side docs so teams can quickly decide mode based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transport style&lt;/li&gt;
&lt;li&gt;portability&lt;/li&gt;
&lt;li&gt;mapping behavior&lt;/li&gt;
&lt;li&gt;counter interval semantics&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Docker-based milestone-6 integration tests (M6-6)
&lt;/h3&gt;

&lt;p&gt;We added dedicated tests under:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tests/milestone-6/test_datadog_live_integration.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are intentionally gated and only run when explicitly enabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Files Added/Updated
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/config/runtime.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/config/__init__.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/exporters/factory.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/exporters/datadog_native.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tests/test_config_otlp_env.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tests/test_datadog_exporters.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tests/milestone-6/test_datadog_live_integration.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs/configuration.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs/architecture.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs/development.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation Strategy
&lt;/h2&gt;

&lt;p&gt;We followed the existing exporter architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep collectors unchanged&lt;/li&gt;
&lt;li&gt;Extend runtime config with strict validation and preset resolution&lt;/li&gt;
&lt;li&gt;Reuse OTLP HTTP exporter for Datadog OTLP mode&lt;/li&gt;
&lt;li&gt;Add a dedicated native exporter for Datadog API v1 series&lt;/li&gt;
&lt;li&gt;Add deterministic mapping rules + comprehensive tests&lt;/li&gt;
&lt;li&gt;Add Docker-backed live tests in a milestone-specific folder&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Test Commands and Outputs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Local Datadog-focused test suite
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python3 &lt;span class="nt"&gt;-m&lt;/span&gt; unittest &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  tests.test_config_otlp_env &lt;span class="se"&gt;\&lt;/span&gt;
  tests.test_datadog_exporters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ran 21 tests in 0.008s

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Full local suite
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python3 &lt;span class="nt"&gt;-m&lt;/span&gt; unittest discover &lt;span class="nt"&gt;-s&lt;/span&gt; tests &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ran 42 tests in 0.014s

OK (skipped=1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Docker live Datadog integration tests (milestone-6)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.test.yml run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;RUN_OTLP_INTEGRATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;RUN_DATADOG_LIVE_INTEGRATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;DATADOG_SITE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us5.datadoghq.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;DATADOG_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;REDACTED_DATADOG_API_KEY&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  test-runner &lt;span class="se"&gt;\&lt;/span&gt;
  pytest &lt;span class="nt"&gt;-vv&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-rs&lt;/span&gt; tests/milestone-6/test_datadog_live_integration.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observed output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;collected 2 items

tests/milestone-6/test_datadog_live_integration.py::DatadogLiveIntegrationTests::test_datadog_native_exports_gauge_and_count_metrics PASSED
tests/milestone-6/test_datadog_live_integration.py::DatadogLiveIntegrationTests::test_datadog_otlp_preset_exports_gauge_metric PASSED

2 passed in 2.63s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;With Milestone 6 complete, Datadog users can now choose the integration path that matches their operations model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose &lt;strong&gt;OTLP preset&lt;/strong&gt; for standards-aligned portability&lt;/li&gt;
&lt;li&gt;choose &lt;strong&gt;native mode&lt;/strong&gt; for Datadog-specific control and semantics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both paths are now validated, tested, and documented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contribute
&lt;/h2&gt;

&lt;p&gt;If you're interested in observability agents, OTLP pipelines, or exporter design, contributions are welcome:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful contribution areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;additional Datadog live integration coverage&lt;/li&gt;
&lt;li&gt;CI automation for gated integration scenarios&lt;/li&gt;
&lt;li&gt;docs/examples for production deployments&lt;/li&gt;
&lt;li&gt;future milestone reliability and operability improvements&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>datadog</category>
      <category>telemetry</category>
    </item>
    <item>
      <title>Milestone 5 Complete: New Relic OTLP Integration for Heka Insights Agent</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Tue, 12 May 2026 05:33:12 +0000</pubDate>
      <link>https://dev.to/munirfarhan/milestone-5-complete-new-relic-otlp-integration-for-heka-insights-agent-411f</link>
      <guid>https://dev.to/munirfarhan/milestone-5-complete-new-relic-otlp-integration-for-heka-insights-agent-411f</guid>
      <description>&lt;p&gt;In this milestone, we focused on making &lt;strong&gt;New Relic integration first-class&lt;/strong&gt; in the Heka Insights Agent, while still using the same OTLP HTTP exporter foundation.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Milestone 5 Goal
&lt;/h2&gt;

&lt;p&gt;Milestone 5 was about shipping a reliable, low-friction New Relic path without creating a separate proprietary exporter.&lt;/p&gt;

&lt;p&gt;Scope covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New Relic preset configuration layer&lt;/li&gt;
&lt;li&gt;Automatic New Relic auth header injection&lt;/li&gt;
&lt;li&gt;Endpoint and required field validation&lt;/li&gt;
&lt;li&gt;Documentation updates with practical examples&lt;/li&gt;
&lt;li&gt;Integration tests for preset behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What We Changed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. New Relic preset mode (&lt;code&gt;EXPORTER_TYPE=newrelic_otlp&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;We added a preset resolver that maps New Relic-specific environment variables into OTLP HTTP exporter inputs.&lt;/p&gt;

&lt;p&gt;Required variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NEWRELIC_OTLP_ENDPOINT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEWRELIC_API_KEY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEWRELIC_SERVICE_NAME&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optional variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NEWRELIC_ENVIRONMENT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEWRELIC_HOST_NAME&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Automatic auth header injection
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;EXPORTER_TYPE=newrelic_otlp&lt;/code&gt; is selected, the runtime now injects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;api-key: &amp;lt;NEWRELIC_API_KEY&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No manual &lt;code&gt;OTLP_HTTP_HEADERS&lt;/code&gt; setup is required for baseline New Relic auth.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Precedence behavior
&lt;/h3&gt;

&lt;p&gt;In preset mode, &lt;code&gt;NEWRELIC_*&lt;/code&gt; values take precedence over conflicting generic &lt;code&gt;OTLP_*&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NEWRELIC_API_KEY&lt;/code&gt; overrides any conflicting &lt;code&gt;OTLP_HTTP_HEADERS&lt;/code&gt; &lt;code&gt;api-key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NEWRELIC_SERVICE_NAME&lt;/code&gt; overrides &lt;code&gt;service.name&lt;/code&gt; from &lt;code&gt;OTLP_RESOURCE_ATTRIBUTES&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Validation hardening
&lt;/h3&gt;

&lt;p&gt;We now fail fast on invalid or missing required New Relic settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing required keys -&amp;gt; startup error&lt;/li&gt;
&lt;li&gt;invalid endpoint format -&amp;gt; startup error (must be absolute &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Documentation updates
&lt;/h3&gt;

&lt;p&gt;We updated project docs and examples to include New Relic preset usage and expected test flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands to Run Tests
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Unit tests for config behavior
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python3 &lt;span class="nt"&gt;-m&lt;/span&gt; unittest &lt;span class="nt"&gt;-v&lt;/span&gt; tests.test_config_otlp_env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New Relic Docker integration tests (explicit)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.test.yml run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;RUN_OTLP_INTEGRATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;OTLP_IT_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host.docker.internal &lt;span class="se"&gt;\&lt;/span&gt;
  test-runner &lt;span class="se"&gt;\&lt;/span&gt;
  pytest &lt;span class="nt"&gt;-vv&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-rs&lt;/span&gt; tests/milestone-5/test_newrelic_otlp_integration.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected summary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;collected 3 items
...
3 passed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Full OTLP/HTTP Docker test stack
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.test.yml up &lt;span class="nt"&gt;--build&lt;/span&gt; &lt;span class="nt"&gt;--abort-on-container-exit&lt;/span&gt; &lt;span class="nt"&gt;--exit-code-from&lt;/span&gt; test-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;With Milestone 5 complete, teams can onboard New Relic using a predictable preset path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;less config ambiguity&lt;/li&gt;
&lt;li&gt;safer startup behavior through validation&lt;/li&gt;
&lt;li&gt;standardized OTLP transport path&lt;/li&gt;
&lt;li&gt;stronger confidence through Docker-backed integration tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next steps will continue building on this exporter foundation while keeping the runtime predictable and vendor-friendly.&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>telemetry</category>
      <category>agents</category>
    </item>
    <item>
      <title>Milestone 4 Complete — OTLP HTTP Exporter for Heka Insights Agent</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Wed, 29 Apr 2026 06:49:27 +0000</pubDate>
      <link>https://dev.to/munirfarhan/milestone-4-complete-otlp-http-exporter-for-heka-insights-agent-1chp</link>
      <guid>https://dev.to/munirfarhan/milestone-4-complete-otlp-http-exporter-for-heka-insights-agent-1chp</guid>
      <description>&lt;p&gt;In this milestone, I completed the OTLP HTTP exporter implementation for &lt;strong&gt;Heka Insights Agent&lt;/strong&gt; and validated it with both unit tests and Docker-backed integration tests.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What was implemented in Milestone 4
&lt;/h2&gt;

&lt;p&gt;Milestone 4 includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OTLP HTTP exporter wiring&lt;/li&gt;
&lt;li&gt;OTLP metric payload mapping&lt;/li&gt;
&lt;li&gt;OTLP auth header support&lt;/li&gt;
&lt;li&gt;OTLP resource attribute mapping&lt;/li&gt;
&lt;li&gt;Retry/backoff behavior for transient failures&lt;/li&gt;
&lt;li&gt;Unit test coverage for config + sender + exporter + mapping&lt;/li&gt;
&lt;li&gt;Docker integration tests against a real OpenTelemetry Collector&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Configuration added
&lt;/h2&gt;

&lt;p&gt;OTLP configuration is environment-driven through &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOG_LOCATION=./log/heka_agent.log
CPU_POLL_INTERVAL_SECONDS=10
EXPORTER_TYPE=otlp_http
OTLP_HTTP_ENDPOINT=http://localhost:4318/v1/metrics
OTLP_HTTP_HEADERS=key=Bearer abcd1234
OTLP_RESOURCE_ATTRIBUTES=service.name=heka-insights-agent,host.name=localhost
OTLP_HTTP_TIMEOUT_SECONDS=10
OTLP_HTTP_RETRY_MAX_ATTEMPTS=5
OTLP_HTTP_RETRY_INITIAL_BACKOFF_SECONDS=1
OTLP_HTTP_RETRY_MAX_BACKOFF_SECONDS=5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OTLP_HTTP_HEADERS&lt;/code&gt; format: &lt;code&gt;key=value,key2=value2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OTLP_RESOURCE_ATTRIBUTES&lt;/code&gt; format: &lt;code&gt;key=value,key2=value2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retryable failures:

&lt;ul&gt;
&lt;li&gt;transport errors&lt;/li&gt;
&lt;li&gt;HTTP &lt;code&gt;408&lt;/code&gt;, &lt;code&gt;429&lt;/code&gt;, and &lt;code&gt;5xx&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Non-retryable failures:

&lt;ul&gt;
&lt;li&gt;HTTP &lt;code&gt;400&lt;/code&gt;, &lt;code&gt;401&lt;/code&gt;, &lt;code&gt;403&lt;/code&gt;, &lt;code&gt;404&lt;/code&gt;, and similar client-side errors&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Unit tests
&lt;/h2&gt;

&lt;p&gt;Unit tests cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OTLP env parsing and validation&lt;/li&gt;
&lt;li&gt;OTLP payload mapping&lt;/li&gt;
&lt;li&gt;OTLP HTTP sender behavior&lt;/li&gt;
&lt;li&gt;Retry/backoff behavior&lt;/li&gt;
&lt;li&gt;Exporter initialization and wiring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run unit tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python3 &lt;span class="nt"&gt;-m&lt;/span&gt; unittest discover &lt;span class="nt"&gt;-s&lt;/span&gt; tests &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unit test output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ran 27 tests in 0.008s

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Integration tests (Docker + real collector)
&lt;/h2&gt;

&lt;p&gt;Integration tests validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth success (&lt;code&gt;200&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;auth reject path (&lt;code&gt;401&lt;/code&gt;) and no retry on non-retryable status&lt;/li&gt;
&lt;li&gt;no-auth collector path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run OTLP integration tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;RUN_OTLP_INTEGRATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python3 &lt;span class="nt"&gt;-m&lt;/span&gt; unittest &lt;span class="nt"&gt;-v&lt;/span&gt; tests.test_otlp_http_integration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integration test output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test_auth_rejected_without_retry_for_401 ... ok
test_auth_success_with_bearer_header ... ok
test_no_auth_collector_accepts_without_headers ... ok

----------------------------------------------------------------------
Ran 3 tests in 2.417s

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Collector config used in tests
&lt;/h2&gt;

&lt;p&gt;The project includes collector fixtures under &lt;code&gt;tests/fixtures/otlp/&lt;/code&gt;, including auth-required and no-auth variants for scenario testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final result
&lt;/h2&gt;

&lt;p&gt;Milestone 4 now has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;working OTLP HTTP exporter&lt;/li&gt;
&lt;li&gt;production-style config controls&lt;/li&gt;
&lt;li&gt;retry/backoff logic for transient failures&lt;/li&gt;
&lt;li&gt;unit + integration test coverage&lt;/li&gt;
&lt;li&gt;updated docs and run instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repo again: &lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>devops</category>
      <category>telemetry</category>
    </item>
    <item>
      <title>Milestone 4 (Part 1): Implementing OTLP HTTP Core in Heka Insights Agent (M4-1, M4-2)</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Mon, 27 Apr 2026 09:57:30 +0000</pubDate>
      <link>https://dev.to/munirfarhan/milestone-4-part-1-implementing-otlp-http-core-in-heka-insights-agent-m4-1-m4-2-2a79</link>
      <guid>https://dev.to/munirfarhan/milestone-4-part-1-implementing-otlp-http-core-in-heka-insights-agent-m4-1-m4-2-2a79</guid>
      <description>&lt;h1&gt;
  
  
  Milestone 4 (Part 1): Implementing OTLP HTTP Core in Heka Insights Agent (M4-1, M4-2)
&lt;/h1&gt;

&lt;p&gt;Heka Insights Agent already had a canonical metrics pipeline from Milestone 3.&lt;br&gt;&lt;br&gt;
In this part of Milestone 4, I implemented the OTLP HTTP core in two focused steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M4-1&lt;/code&gt;: Canonical metrics -&amp;gt; OTLP payload mapping layer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;M4-2&lt;/code&gt;: OTLP HTTP request sender and exporter wiring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post covers only these two items. Auth headers, resource attributes, retry/compression controls are intentionally deferred to later M4 tasks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why This Split Matters
&lt;/h2&gt;

&lt;p&gt;By separating mapping from transport, we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stable internal metric model&lt;/li&gt;
&lt;li&gt;explicit OTLP payload construction&lt;/li&gt;
&lt;li&gt;transport logic that can evolve independently&lt;/li&gt;
&lt;li&gt;clean foundation for New Relic/Datadog-style OTLP integrations later&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What Was Implemented
&lt;/h2&gt;
&lt;h3&gt;
  
  
  M4-1: OTLP Payload Mapping Layer
&lt;/h3&gt;

&lt;p&gt;I added a dedicated mapper that converts canonical metric records into OTLP HTTP JSON payloads.&lt;/p&gt;

&lt;p&gt;Core behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validates required canonical fields before send&lt;/li&gt;
&lt;li&gt;supports explicit type mapping:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gauge&lt;/code&gt; -&amp;gt; OTLP &lt;code&gt;gauge.dataPoints&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;counter&lt;/code&gt; -&amp;gt; OTLP &lt;code&gt;sum.dataPoints&lt;/code&gt; with cumulative temporality&lt;/li&gt;
&lt;li&gt;maps canonical labels to OTLP metric attributes&lt;/li&gt;
&lt;li&gt;maps &lt;code&gt;timestamp_unix_ms&lt;/code&gt; to OTLP &lt;code&gt;timeUnixNano&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;rejects malformed metrics early with explicit errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: malformed payloads are blocked before network transport.&lt;/p&gt;
&lt;h3&gt;
  
  
  M4-2: OTLP HTTP Sender + Exporter
&lt;/h3&gt;

&lt;p&gt;I added OTLP HTTP sender/exporter flow and wired it into exporter selection.&lt;/p&gt;

&lt;p&gt;Core behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;EXPORTER_TYPE=otlp_http&lt;/code&gt; now creates OTLP exporter&lt;/li&gt;
&lt;li&gt;validates OTLP endpoint format (&lt;code&gt;http/https&lt;/code&gt; absolute URL) at startup&lt;/li&gt;
&lt;li&gt;fails fast when endpoint is missing/invalid&lt;/li&gt;
&lt;li&gt;sends JSON payload via HTTP &lt;code&gt;POST&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;treats only &lt;code&gt;2xx&lt;/code&gt; responses as success&lt;/li&gt;
&lt;li&gt;raises explicit errors for HTTP failures and transport errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: working end-to-end OTLP HTTP delivery with fail-fast startup safety.&lt;/p&gt;
&lt;h2&gt;
  
  
  Local Test Setup with OpenTelemetry Collector (Docker)
&lt;/h2&gt;

&lt;p&gt;I used OTel Collector debug exporter to validate incoming metrics.&lt;/p&gt;
&lt;h3&gt;
  
  
  Collector config (&lt;code&gt;otel-collector-config.yaml&lt;/code&gt;)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;protocols&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0:4318&lt;/span&gt;

&lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Run collector
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 4318:4318 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/otel-collector-config.yaml:/etc/otelcol/config.yaml"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  otel/opentelemetry-collector:latest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/otelcol/config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Agent &lt;code&gt;.env&lt;/code&gt; for this test
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOG_LOCATION=./log/heka_agent.log
CPU_POLL_INTERVAL_SECONDS=10
EXPORTER_TYPE=otlp_http
OTLP_HTTP_ENDPOINT=http://localhost:4318/v1/metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Run agent
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python src/main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Verification Signals
&lt;/h2&gt;

&lt;p&gt;From runtime behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agent starts with &lt;code&gt;exporter_type=otlp_http&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;collector logs periodic metric batches every ~10 seconds&lt;/li&gt;
&lt;li&gt;no exporter exceptions during dispatch&lt;/li&gt;
&lt;li&gt;first cycle has fewer points due to CPU warm-up, then normalizes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example collector signal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;resource metrics: 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;metrics: 24&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data points: 24&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Tests Added
&lt;/h2&gt;

&lt;p&gt;I added focused tests for M4-1/M4-2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;payload mapping correctness (gauge/counter, labels, timestamps)&lt;/li&gt;
&lt;li&gt;validation failures for malformed canonical metrics&lt;/li&gt;
&lt;li&gt;HTTP sender request behavior and error handling&lt;/li&gt;
&lt;li&gt;exporter wiring and missing-endpoint startup failure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All tests pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python3 &lt;span class="nt"&gt;-m&lt;/span&gt; unittest discover &lt;span class="nt"&gt;-s&lt;/span&gt; tests &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Is Intentionally Not Included Yet
&lt;/h2&gt;

&lt;p&gt;Deferred to later M4 items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth headers (&lt;code&gt;M4-3&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;resource attribute mapping (&lt;code&gt;M4-4&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;timeout/compression/retry controls (&lt;code&gt;M4-5&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;broader OTLP docs and expanded test matrix (&lt;code&gt;M4-6&lt;/code&gt;, &lt;code&gt;M4-7&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;M4-1 and M4-2 establish the OTLP core path: canonical metrics are now mapped deterministically and sent over HTTP with fail-fast validation.&lt;br&gt;&lt;br&gt;
This gives a production-friendly base to layer auth, resource metadata, and resiliency controls next.&lt;/p&gt;

&lt;p&gt;Repo URL: &lt;a href="https://github.com/ronin1770/heka-insights-agent" rel="noopener noreferrer"&gt;https://github.com/ronin1770/heka-insights-agent&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>devops</category>
      <category>telemetry</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Heka-Insights-Agent: Milestone M3-4: Fail-Fast Exporter Validation at Startup</title>
      <dc:creator>Farhan Munir</dc:creator>
      <pubDate>Fri, 24 Apr 2026 06:30:06 +0000</pubDate>
      <link>https://dev.to/munirfarhan/heka-insights-agent-milestone-m3-4-fail-fast-exporter-validation-at-startup-14p</link>
      <guid>https://dev.to/munirfarhan/heka-insights-agent-milestone-m3-4-fail-fast-exporter-validation-at-startup-14p</guid>
      <description>&lt;h1&gt;
  
  
  Milestone M3-4: Fail-Fast Exporter Validation at Startup
&lt;/h1&gt;

&lt;p&gt;On &lt;strong&gt;April 24, 2026&lt;/strong&gt;, I completed &lt;strong&gt;M3-4&lt;/strong&gt; in &lt;code&gt;heka-insights-agent&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M3-4: Add configuration validation for exporter settings&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This milestone closed a critical gap in the exporter foundation by removing silent fallback behavior and enforcing explicit startup failures for invalid exporter configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;In Milestone M3-3, we routed output through the exporter interface and lifecycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;initialize()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export(metrics)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shutdown()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That established the architecture.&lt;br&gt;&lt;br&gt;
M3-4 focused on correctness and operational safety: startup must fail early when exporter configuration is invalid or points to an unimplemented adapter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Before M3-4
&lt;/h2&gt;

&lt;p&gt;Prior behavior was permissive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invalid &lt;code&gt;EXPORTER_TYPE&lt;/code&gt; values defaulted back to &lt;code&gt;console&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;unimplemented exporter types also downgraded to &lt;code&gt;console&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this was risky:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;misconfiguration could go unnoticed in production&lt;/li&gt;
&lt;li&gt;users could think they were exporting to one backend while actually exporting to console&lt;/li&gt;
&lt;li&gt;behavior violated milestone acceptance criteria requiring explicit errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  M3-4 Goals
&lt;/h2&gt;

&lt;p&gt;The implementation targeted three concrete outcomes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;invalid &lt;code&gt;EXPORTER_TYPE&lt;/code&gt; must fail fast with a clear startup error&lt;/li&gt;
&lt;li&gt;configured but unimplemented exporter adapters must fail fast with a clear startup error&lt;/li&gt;
&lt;li&gt;docs must reflect strict validation (remove pre-M3-4 fallback messaging)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implementation Summary
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1) Strict validation in runtime config
&lt;/h2&gt;

&lt;p&gt;Updated &lt;code&gt;src/config/runtime.py&lt;/code&gt; in &lt;code&gt;get_exporter_type(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Behavior now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing &lt;code&gt;EXPORTER_TYPE&lt;/code&gt; still defaults to &lt;code&gt;console&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;unsupported value now raises &lt;code&gt;RuntimeError&lt;/code&gt; with explicit supported values list&lt;/li&gt;
&lt;li&gt;optional logger records an error message before raising&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This changed exporter selection from “best-effort fallback” to deterministic validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Removed fallback from exporter factory
&lt;/h2&gt;

&lt;p&gt;Updated &lt;code&gt;src/exporters/factory.py&lt;/code&gt; in &lt;code&gt;create_exporter(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Behavior now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;console&lt;/code&gt; returns &lt;code&gt;ConsoleExporter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;other configured values currently raise &lt;code&gt;RuntimeError&lt;/code&gt; because adapters are not implemented yet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is intentional. It prevents false confidence and makes readiness of each exporter explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Documentation updated to M3-4 semantics
&lt;/h2&gt;

&lt;p&gt;Updated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docs/configuration.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both now state that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unsupported exporter values fail fast&lt;/li&gt;
&lt;li&gt;unimplemented exporters fail fast&lt;/li&gt;
&lt;li&gt;only missing value defaults to &lt;code&gt;console&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removed the “fallback to console with warning” wording from the pre-M3-4 behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation Performed
&lt;/h2&gt;

&lt;p&gt;Validation included compile checks and runtime behavior checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile validation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;python3 -m compileall src&lt;/code&gt; passed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Behavior validation
&lt;/h2&gt;

&lt;p&gt;Tested startup resolution paths for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing &lt;code&gt;EXPORTER_TYPE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXPORTER_TYPE=console&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXPORTER_TYPE=invalid_value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXPORTER_TYPE=otlp_http&lt;/code&gt; (declared but not implemented adapter)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observed results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing value -&amp;gt; resolves to &lt;code&gt;console&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;console&lt;/code&gt; -&amp;gt; exporter creation succeeds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;invalid_value&lt;/code&gt; -&amp;gt; immediate &lt;code&gt;RuntimeError&lt;/code&gt; with supported-values message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;otlp_http&lt;/code&gt; -&amp;gt; immediate &lt;code&gt;RuntimeError&lt;/code&gt; stating exporter not implemented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These outcomes align with M3-4 requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this change matters operationally
&lt;/h2&gt;

&lt;p&gt;Fail-fast startup validation improves reliability in real deployments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;misconfigurations are caught immediately&lt;/li&gt;
&lt;li&gt;no hidden routing to fallback output&lt;/li&gt;
&lt;li&gt;deployment behavior is explicit and auditable&lt;/li&gt;
&lt;li&gt;future exporter rollout can be gated by implementation readiness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially important when teams automate deployments and rely on env-based configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architectural Impact
&lt;/h2&gt;

&lt;p&gt;After M3-4, exporter behavior is now strictly layered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;config validates selector&lt;/li&gt;
&lt;li&gt;factory enforces implementation availability&lt;/li&gt;
&lt;li&gt;runtime starts only on valid+implemented exporter path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives us a clean foundation for adding real transports (&lt;code&gt;otlp_http&lt;/code&gt;, &lt;code&gt;datadog_native&lt;/code&gt;, &lt;code&gt;newrelic_otlp&lt;/code&gt;) without changing collector logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;The natural next step after M3-4 is M3-5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document exporter lifecycle and responsibilities in architecture docs&lt;/li&gt;
&lt;li&gt;include startup validation expectations as part of operational guidance&lt;/li&gt;
&lt;li&gt;capture adapter implementation contract for future backend integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;M3-4 makes sure the system fails loudly when exporter config is wrong, which is exactly what a transport foundation should do before adding real outbound integrations.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>python</category>
      <category>telemetry</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
