<?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: Manju Vasanth</title>
    <description>The latest articles on DEV Community by Manju Vasanth (@manju_vasanth).</description>
    <link>https://dev.to/manju_vasanth</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%2F4025549%2F6bfbedb5-d065-4b16-9609-f1886065d255.jpg</url>
      <title>DEV Community: Manju Vasanth</title>
      <link>https://dev.to/manju_vasanth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manju_vasanth"/>
    <language>en</language>
    <item>
      <title>I Taught an AI Agent to Debug Workday Integrations Like a Senior Consultant</title>
      <dc:creator>Manju Vasanth</dc:creator>
      <pubDate>Fri, 24 Jul 2026 16:50:06 +0000</pubDate>
      <link>https://dev.to/manju_vasanth/i-taught-an-ai-agent-to-debug-workday-integrations-like-a-senior-consultant-5bdd</link>
      <guid>https://dev.to/manju_vasanth/i-taught-an-ai-agent-to-debug-workday-integrations-like-a-senior-consultant-5bdd</guid>
      <description>&lt;p&gt;&lt;em&gt;Built for the Agents of SigNoz hackathon: OpenTelemetry + SigNoz + MCP + a decade of enterprise integration scar tissue.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;When a Workday integration fails, the error message almost never tells you the real story. A raw &lt;code&gt;403 Forbidden&lt;/code&gt; does not say "your Integration System User's security group is missing a domain security policy." Figuring that out takes a person who has been burned by it before. I have spent years being that person, so for this hackathon I asked a specific question: can I bottle that tribal knowledge into an agent that reads telemetry and answers like a senior consultant would?&lt;/p&gt;

&lt;p&gt;By the end of the week, the answer was yes, and the road there included my own code crashing in ways I did not expect, twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A mock Workday tenant.&lt;/strong&gt; A Python/Flask simulator I built to practice integration patterns: SOAP endpoints, RaaS reports, and an Extend-style canvas that runs a config-driven, multi-step supervisory org provisioning orchestration (validate input, check existence, build a SOAP payload, call the tenant, extract results).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full observability via SigNoz.&lt;/strong&gt; OpenTelemetry instrumentation on every orchestration step, streaming traces, logs, and dashboards into self-hosted SigNoz, deployed with Foundry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An AI diagnostic agent.&lt;/strong&gt; A Python agent that talks to SigNoz's MCP server, pulls the newest failed trace, finds the failing step, and maps it to a Workday-specific root cause with fix steps.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foeoalxewzi4gapfjucjn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foeoalxewzi4gapfjucjn.png" alt=" " width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Instrumenting a Config-Driven Pipeline
&lt;/h2&gt;

&lt;p&gt;The simulator's orchestration engine executes steps from a JSON store, which made instrumentation surprisingly clean: wrap the step executor once, and every step gets a span automatically. The core of it:&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;def&lt;/span&gt; &lt;span class="nf"&gt;exec_steps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;typ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ref&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;span_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;step-%02d.%s.%s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;_tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_as_current_span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;span_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;step.index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;step.type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;step.ref&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chaos.injected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;exec_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record_exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One edit, and the SigNoz waterfall went from anonymous &lt;code&gt;GET&lt;/code&gt;/&lt;code&gt;POST&lt;/code&gt; spans to a readable business flow: &lt;code&gt;step-02.send-http-request.CheckExists&lt;/code&gt;, &lt;code&gt;step-05.send-http-request.CallHumanResources&lt;/code&gt;. I also hooked the engine's existing log function so every step message becomes a span event and a trace-correlated log line. My old "eye-catcher" debug strings suddenly carried trace IDs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo1rozn32bhjzqzyis6j7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo1rozn32bhjzqzyis6j7.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chaos Injection: Breaking It on Purpose
&lt;/h2&gt;

&lt;p&gt;To give the agent something to diagnose, I added config-driven failure injection. Adding one key to any step in the flow store simulates a realistic Workday failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CallHumanResources"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"inject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"403"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modes cover the failures I actually see in integration work: 400 (malformed WQL, usually an unescaped apostrophe in a name filter), 401 (expired ISU token), 403 (missing ISSG domain permission), 404 (bad reference), timeout, and empty result sets.&lt;/p&gt;

&lt;p&gt;Here is the part the tutorials do not tell you: &lt;strong&gt;my first injected failure crashed my own application.&lt;/strong&gt; The screen handler behind the orchestration had only ever rendered success. When the flow returned an error result, it died on a &lt;code&gt;NoneType&lt;/code&gt; at line 196, then, after I guarded that line, at line 197. Chaos engineering found my unhandled error path before it found anything else. The traceback, fittingly, was waiting for me in SigNoz's Exceptions view, grouped and linked to the exact trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Agent: Telemetry In, Workday Answers Out
&lt;/h2&gt;

&lt;p&gt;SigNoz ships an MCP server (enabled through one block in Foundry's &lt;code&gt;casting.yaml&lt;/code&gt;), and it exposes 41 tools. My agent uses three: &lt;code&gt;signoz_search_traces&lt;/code&gt; to find the newest ERROR trace for the service, &lt;code&gt;signoz_get_trace_details&lt;/code&gt; for the span tree, and the span attributes and status messages as evidence.&lt;/p&gt;

&lt;p&gt;The diagnosis itself is a rule table built from experience, the mapping I would apply manually on a support ticket. The 403 entry, for example:&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP 403|Forbidden|lacks domain security&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ISSG missing domain security policy permission&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The ISU authenticated successfully but its security group lacks &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Get/Put access on the target domain.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Grant the ISU&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s security group the required domain security policy permission&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Activate pending security policy changes in the tenant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Re-run the step; a 200/201 confirms the grant took effect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a run fails, the agent prints the failing step, the root cause in Workday language, fix steps, and a pipeline map with the failure flagged. It also discloses when a failure was injected, if &lt;code&gt;chaos.injected&lt;/code&gt; is present, the report says so. An agent that quietly presents staged failures as organic ones would be a demo trick, not a tool.&lt;/p&gt;

&lt;p&gt;A confession that belongs in this section: &lt;strong&gt;the agent's very first run failed with a 403 of its own.&lt;/strong&gt; I had created the SigNoz service account but skipped the role assignment step, so the MCP server rejected every query with "only viewers/editors/admins can access this resource." My permission-diagnosing agent was blocked by a missing permission. I fixed it the way its own rule table would have suggested.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dashboard That Called My Bluff
&lt;/h2&gt;

&lt;p&gt;I built a four-panel "Workday Integration Health" dashboard with the Query Builder: p95 latency per step, failures by step, error logs, and a formula panel computing success rate as &lt;code&gt;A/B*100&lt;/code&gt; over root spans.&lt;/p&gt;

&lt;p&gt;The formula panel immediately exposed a design flaw. It read &lt;strong&gt;100% success&lt;/strong&gt; while injected failures were clearly happening. The reason: my chaos hook failed the &lt;em&gt;step&lt;/em&gt; span but let the flow complete gracefully, so the root &lt;code&gt;orchestration.run&lt;/code&gt; span stayed clean. A run with a failed step was counting as a successful run. One line in the root wrapper fixed it, propagate ERROR to the root if any step in the trace log failed, and the panel dropped to an honest 92.5%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1xzq8xairqiheolhnim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1xzq8xairqiheolhnim.png" alt=" " width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I finished with an alert rule on the failure count (above 0, at least once, 5-minute rolling window). One injected run later:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fov8pvblmz72cmkvyhe9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fov8pvblmz72cmkvyhe9g.png" alt=" " width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Chaos finds your bugs first.&lt;/strong&gt; Both crashes this week were in my code's error paths, not in the failures I injected. If your system has never seen a failure, your error handling is untested by definition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace-first debugging beats log-first.&lt;/strong&gt; This project exists partly because SigNoz found a 93x slowdown in this same simulator the week before the hackathon, a Windows IPv6 fallback on &lt;code&gt;localhost&lt;/code&gt; that logs could never have shown me (I wrote that story up separately). The waterfall answers &lt;em&gt;where&lt;/em&gt;, span attributes answer &lt;em&gt;why&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain knowledge is the agent's moat.&lt;/strong&gt; The MCP plumbing took an afternoon. The part that makes the agent useful, knowing that a 403 on a SOAP call usually means an ISSG policy gap and what to do about it, took years, and no amount of telemetry replaces it. Telemetry just delivers it faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest metrics require design.&lt;/strong&gt; My dashboard showed 100% success while things were failing. Metrics report what you measure, not what you mean.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I Would Do Next
&lt;/h2&gt;

&lt;p&gt;A chat interface over the agent, richer WQL-level diagnosis (empty-result drift is a silent killer in reporting integrations), and pointing the same pattern at real integration platforms. Nothing here is Workday-specific in principle: named business-step spans plus a domain rule table plus an LLM to compose the narrative would work for any enterprise pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;One week, one simulator, and a full observability loop: named traces, correlated logs, a live dashboard, a firing alert, and an agent that reads it all through MCP and answers like a colleague. The repo (with the Foundry &lt;code&gt;casting.yaml&lt;/code&gt; and lock file for one-command reproduction) is here: &lt;a href="https://github.com/ManjuVasanth/signoz-workday-agent" rel="noopener noreferrer"&gt;https://github.com/ManjuVasanth/signoz-workday-agent&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the &lt;a href="https://www.wemakedevs.org/hackathons/signoz" rel="noopener noreferrer"&gt;Agents of SigNoz&lt;/a&gt; hackathon by WeMakeDevs and SigNoz.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI disclosure: I used Claude (Anthropic) as an assistant for debugging guidance, code drafting, and editing this post. The system design, Workday domain knowledge, testing, and all screenshots are from my own environment and experience.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>signoz</category>
      <category>ai</category>
      <category>opentelemetry</category>
      <category>observability</category>
    </item>
    <item>
      <title>My API Was 4 Seconds Slow. The Fix Was 9 Characters.</title>
      <dc:creator>Manju Vasanth</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:20:02 +0000</pubDate>
      <link>https://dev.to/manju_vasanth/my-api-was-4-seconds-slow-the-fix-was-9-characters-51pl</link>
      <guid>https://dev.to/manju_vasanth/my-api-was-4-seconds-slow-the-fix-was-9-characters-51pl</guid>
      <description>&lt;p&gt;I signed up for the &lt;strong&gt;Agents of SigNoz&lt;/strong&gt; hackathon planning to warm up with the pre-event blog challenge: self-host SigNoz, send some data, write about a feature I liked. A quiet Saturday afternoon task.&lt;/p&gt;

&lt;p&gt;Instead, SigNoz found a real performance bug in my own code within 30 minutes of sending it traffic. This is that story.&lt;/p&gt;

&lt;h2&gt;
  
  
  The App: A Mock Workday Tenant
&lt;/h2&gt;

&lt;p&gt;To practice Workday integration patterns without touching a real tenant, I built a Python/Flask simulator that mimics a Workday environment: SOAP endpoints, RaaS reports, an Extend-style orchestration canvas, the works.&lt;/p&gt;

&lt;p&gt;The flow I care about is a supervisory org provisioning orchestration. One button click runs a config-driven, multi-step pipeline: WQL lookups, widget value extraction, and SOAP calls against the simulator's own endpoints. It worked. It just always felt a little... sluggish. I assumed that was the cost of a chatty multi-step flow and moved on.&lt;/p&gt;

&lt;p&gt;Spoiler: it was not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Hosting SigNoz (Note: Docker Compose Is Deprecated)
&lt;/h2&gt;

&lt;p&gt;First surprise: if you follow older tutorials and clone the SigNoz repo looking for &lt;code&gt;deploy/docker&lt;/code&gt;, it's gone. SigNoz recently moved installation to &lt;strong&gt;Foundry&lt;/strong&gt;, a new CLI (&lt;code&gt;foundryctl&lt;/code&gt;) that generates and deploys your whole stack from one declarative YAML file. It's new enough that barely anyone has blogged about it yet.&lt;/p&gt;

&lt;p&gt;The entire install was three steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Install foundryctl&lt;/strong&gt; (I'm on Windows, I grabbed the release binary and added it to PATH; on Mac/Linux there's a one-line install script).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Create &lt;code&gt;casting.yaml&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Installation&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;signoz&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;flavor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;compose&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Deploy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;foundryctl cast &lt;span class="nt"&gt;-f&lt;/span&gt; casting.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Foundry validated my Docker setup, generated Compose files into a &lt;code&gt;pours/&lt;/code&gt; directory, and started everything: SigNoz UI, OTel ingester, ClickHouse, ClickHouse Keeper, and Postgres.&lt;br&gt;
&lt;/p&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; pours/deployment/compose.yaml ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five services, all healthy. UI on &lt;code&gt;http://localhost:8080&lt;/code&gt;, OTLP ingestion on 4317/4318. From zero to a running observability stack in under 15 minutes, most of which was image pulls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9kbc00j5qsb0ythhykrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9kbc00j5qsb0ythhykrw.png" alt=" " width="799" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Instrumenting Flask With Zero Code Changes
&lt;/h2&gt;

&lt;p&gt;I wanted a baseline before writing any custom spans, so I used OpenTelemetry auto-instrumentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then launched my app through the OTel wrapper:&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;OTEL_RESOURCE_ATTRIBUTES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;service.name&lt;span class="o"&gt;=&lt;/span&gt;mock-workday-orchestrate &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4317 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;grpc &lt;span class="se"&gt;\&lt;/span&gt;
opentelemetry-instrument python workday_ui.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No code edits. The wrapper auto-instruments Flask and the &lt;code&gt;requests&lt;/code&gt; library, so every incoming route and every outgoing HTTP call becomes a span.&lt;/p&gt;

&lt;p&gt;I clicked through my orchestration flow 10-15 times to generate traffic, then opened SigNoz.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First Look: Something Is Wrong
&lt;/h2&gt;

&lt;p&gt;The Services page populated immediately: latency percentiles, request rate, Apdex, and a key operations table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fku46t6lc91nvhuh4xeif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fku46t6lc91nvhuh4xeif.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it did not look good. My orchestration endpoint showed &lt;strong&gt;p99 latency of 4.21 seconds&lt;/strong&gt;, and the Apdex score was sliding downhill with every run. For a local app calling itself on the same machine, that's absurd.&lt;/p&gt;

&lt;p&gt;Time to open a trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Waterfall: 99.5% of the Time Was Missing
&lt;/h2&gt;

&lt;p&gt;I clicked into a 4.14 second trace for &lt;code&gt;POST /extend/screen/create-sup-org&lt;/code&gt;. The flame graph and waterfall showed 5 spans:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fukv63csgopimoyc45nli.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fukv63csgopimoyc45nli.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;POST /extend/screen/create-sup-org   4.14s   ← root
 ├─ GET  (client span)               2.05s
 │   └─ GET /tenant/soap/...         3.7ms
 └─ POST (client span)               2.08s
     └─ POST /tenant/soap/...        20.35ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things jumped out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, the two internal calls ran sequentially and each took almost exactly 2 seconds. Suspiciously round, suspiciously identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second&lt;/strong&gt;, and this is the part that made me sit up: when I clicked the inner POST server span, the Span details panel showed it took &lt;strong&gt;20.35ms, just 0.49% of total execution time&lt;/strong&gt;. The actual handler doing the SOAP work was fast. The client span wrapping it took 2.08 seconds.&lt;/p&gt;

&lt;p&gt;So roughly 2 seconds per call was being spent somewhere between "my code initiated the request" and "my server started handling it." On localhost. Twice per flow.&lt;/p&gt;

&lt;p&gt;I didn't have any &lt;code&gt;time.sleep()&lt;/code&gt; in the orchestration path (I grepped to be sure). This was real, invisible overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Smoking Gun Was a Span Attribute
&lt;/h2&gt;

&lt;p&gt;The answer was sitting in the Span details panel the whole time, in the request attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;http.url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8443/tenant/soap/human_resources"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqcto2qspxrdw0kugxwls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqcto2qspxrdw0kugxwls.png" alt=" " width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That word, &lt;code&gt;localhost&lt;/code&gt;, is the entire bug.&lt;/p&gt;

&lt;p&gt;Here's what happens on Windows: when Python's &lt;code&gt;requests&lt;/code&gt; library connects to &lt;code&gt;localhost&lt;/code&gt;, the name resolves to both the IPv6 address (&lt;code&gt;::1&lt;/code&gt;) and the IPv4 address (&lt;code&gt;127.0.0.1&lt;/code&gt;), and IPv6 gets tried first. My Flask dev server was bound to IPv4 only. So every single internal call:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attempts a connection to &lt;code&gt;::1&lt;/code&gt; (IPv6)&lt;/li&gt;
&lt;li&gt;Waits for that attempt to fail (roughly 2 seconds)&lt;/li&gt;
&lt;li&gt;Falls back to &lt;code&gt;127.0.0.1&lt;/code&gt; (IPv4)&lt;/li&gt;
&lt;li&gt;Connects instantly, handler responds in milliseconds&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A fixed 2-second tax on every internal HTTP call, completely invisible in application logs, because the application code was never slow. My "chatty flow is just sluggish" assumption had been this bug all along.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 9-Character Fix
&lt;/h2&gt;

&lt;p&gt;Replace &lt;code&gt;localhost&lt;/code&gt; with &lt;code&gt;127.0.0.1&lt;/code&gt; in the URLs my server calls at runtime.&lt;/p&gt;

&lt;p&gt;One wrinkle worth sharing: my orchestration is config-driven, so the step URLs don't only live in Python source. They also live in a saved flow store (&lt;code&gt;orchestrate_store.json&lt;/code&gt;). My first fix edited the Python defaults, restarted, and changed nothing, because the running flow loaded its URLs from the JSON store. Tracing the &lt;em&gt;actual&lt;/em&gt; &lt;code&gt;http.url&lt;/code&gt; attribute in SigNoz is what proved the old value was still live. One &lt;code&gt;sed&lt;/code&gt; across the config and source files later:&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;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt;.bak &lt;span class="s1"&gt;'s|http://localhost:8443|http://127.0.0.1:8443|g'&lt;/span&gt; orchestrate_store.json &lt;span class="k"&gt;*&lt;/span&gt;.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart, rerun the flow, open the newest trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before and After
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0z158zoddme2j0vg5d0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0z158zoddme2j0vg5d0r.png" alt=" " width="799" height="439"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                     Before      After
Root span            4.18s   →   45ms
Internal GET         2.06s   →   11.4ms
Internal POST        2.11s   →   26.1ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.18 seconds down to 45 milliseconds. A 93x improvement&lt;/strong&gt;, from changing 9 characters, found by reading one span attribute.&lt;/p&gt;

&lt;p&gt;The new waterfall is beautiful: the client spans now hug their server spans instead of dwarfing them. And the Span details confirm the fix took: &lt;code&gt;http.host: "127.0.0.1:8443"&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Favorite Feature: The Trace Waterfall + Span Attributes
&lt;/h2&gt;

&lt;p&gt;The blog prompt asks for the feature I liked most, and after this experience it's not close: &lt;strong&gt;the trace detail view&lt;/strong&gt;, specifically the combination of the waterfall and the Span details attribute panel.&lt;/p&gt;

&lt;p&gt;Here's why. Logs told me nothing about this bug. My handler logs showed fast, healthy requests, because the handler &lt;em&gt;was&lt;/em&gt; fast and healthy. Metrics alone would have told me "p99 is 4 seconds" without telling me where the time went.&lt;/p&gt;

&lt;p&gt;The waterfall answered &lt;strong&gt;where&lt;/strong&gt;: not in my handler (20ms), but in the client-side gap around it (2s). The span attributes answered &lt;strong&gt;why&lt;/strong&gt;: the &lt;code&gt;http.url&lt;/code&gt; showed exactly which hostname the live code was calling, which both exposed the IPv6 fallback and caught my incomplete first fix when the config store was still serving the old URL. Observation, localization, root cause, and verification, all in one screen, with zero custom instrumentation.&lt;/p&gt;

&lt;p&gt;Honorable mention to &lt;strong&gt;Foundry&lt;/strong&gt;. Coming from the Workday world where I think in config-driven deployments, "describe your stack in one YAML, run one command" felt immediately familiar, and it worked first try on Windows.&lt;/p&gt;

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

&lt;p&gt;This was supposed to be a warm-up, and it accidentally became a genuine debugging war story. For the main hackathon (Track 01, AI &amp;amp; Agent Observability), I'm building on this exact foundation: manual OpenTelemetry spans for every step of the orchestration pipeline, config-driven failure injection (401s, 403s, timeouts), and an AI diagnostic agent that reads SigNoz traces to explain &lt;em&gt;why&lt;/em&gt; an integration step failed, not just that it did.&lt;/p&gt;

&lt;p&gt;If a single auto-instrumented afternoon found a 93x slowdown, I'm very curious what step-level tracing will turn up.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the &lt;a href="https://www.wemakedevs.org/hackathons/signoz" rel="noopener noreferrer"&gt;Agents of SigNoz&lt;/a&gt; hackathon by WeMakeDevs and SigNoz. SigNoz is open source and OpenTelemetry-native; the self-host docs are &lt;a href="https://signoz.io/docs/install/self-host/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI disclosure: I used Claude (Anthropic) as an assistant for debugging guidance and drafting this post. The setup, investigation, fix, and all screenshots are from my own environment.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>signoz</category>
      <category>opentelemetry</category>
      <category>observability</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
