<?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: Sufiyan Khan S</title>
    <description>The latest articles on DEV Community by Sufiyan Khan S (@sufiyan799).</description>
    <link>https://dev.to/sufiyan799</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%2F4034938%2F27ba0b65-c7b7-42c9-bba2-240db518c24b.png</url>
      <title>DEV Community: Sufiyan Khan S</title>
      <link>https://dev.to/sufiyan799</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sufiyan799"/>
    <language>en</language>
    <item>
      <title>Two of the three bugs I found with SigNoz weren't in my code</title>
      <dc:creator>Sufiyan Khan S</dc:creator>
      <pubDate>Sat, 18 Jul 2026 08:26:43 +0000</pubDate>
      <link>https://dev.to/sufiyan799/two-of-the-three-bugs-i-found-with-signoz-werent-in-my-code-4hhc</link>
      <guid>https://dev.to/sufiyan799/two-of-the-three-bugs-i-found-with-signoz-werent-in-my-code-4hhc</guid>
      <description>&lt;p&gt;I set out to do something simple for the Agents of SigNoz hackathon: build a small RAG service, point OpenTelemetry at a self-hosted SigNoz, and see what the traces told me. The plan took an afternoon. Almost nothing went the way I assumed it would, and the most useful things I learned came from the trace data disagreeing with me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup: SigNoz via Foundry, on a machine that had no Docker
&lt;/h2&gt;

&lt;p&gt;SigNoz deprecated its old &lt;code&gt;install.sh&lt;/code&gt; and the bundled compose files under &lt;code&gt;deploy/&lt;/code&gt; as of v0.130.0. The supported path now is Foundry, a CLI that provisions the stack from a small YAML file:&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="c1"&gt;# casting.yaml&lt;/span&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://signoz.io/foundry.sh | bash
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;Worth flagging, because most of the tutorials I found while searching still tell you to clone the repo and run &lt;code&gt;docker compose up&lt;/code&gt; from &lt;code&gt;deploy/docker&lt;/code&gt;. Those files aren't maintained anymore.&lt;/p&gt;

&lt;p&gt;My laptop is not a generous host: 7.8 GB of RAM total, and no Docker installed at all. The SigNoz docs also carry a warning I wasn't expecting. On Windows you're told to run Docker Engine inside WSL2 rather than Docker Desktop, because ClickHouse Keeper segfaults under Desktop's virtualization layer. So the real install was Ubuntu into WSL2 (under a minute), Docker Engine via get.docker.com (about 80 seconds, zero drama), then Foundry.&lt;/p&gt;

&lt;p&gt;One thing bit me before I got that far. WSL2 defaults to allocating half your RAM, which on my machine came out to 3.7 GiB, just under SigNoz's 4 GB minimum. A &lt;code&gt;.wslconfig&lt;/code&gt; with &lt;code&gt;memory=5GB&lt;/code&gt; fixed it. If your host has 8 GB, budget for this.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;cast&lt;/code&gt; itself was the easy part. It pulled ClickHouse (1.13 GB), the OTel collector, Postgres and Keeper, and had the stack up in about four minutes with no errors. I want to be fair to SigNoz here: the install was the smoothest step of the day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The restart loop that wasn't
&lt;/h2&gt;

&lt;p&gt;Then every &lt;code&gt;docker ps&lt;/code&gt; showed all containers as "Up 2 seconds." Every single time. That is what a crash loop looks like, so I went off chasing memory pressure that didn't exist.&lt;/p&gt;

&lt;p&gt;The actual cause had nothing to do with SigNoz. WSL2 terminates the distro a few seconds after your last command exits. Each time I checked, I was cold-booting systemd, dockerd and the entire SigNoz stack, which then honestly reported "Up 2 seconds," because it had been up for two seconds. The journal gave it away: a fresh &lt;code&gt;Starting docker.service...&lt;/code&gt; with a new PID on every single check.&lt;/p&gt;

&lt;p&gt;The fix is slightly embarrassing. Keep any process alive in the distro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# leave this running in a spare terminal, it matters&lt;/span&gt;
wsl &lt;span class="nt"&gt;-d&lt;/span&gt; Ubuntu &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;infinity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without it, ClickHouse reboots forever and nothing ever reaches healthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  SigNoz will not ingest a single span until you create your account
&lt;/h2&gt;

&lt;p&gt;With the stack finally healthy, my app's exporter started failing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to export traces to localhost:4317, error code: StatusCode.UNAVAILABLE,
error details: ... UNAVAILABLE: ipv6:[::1]:4317: End of TCP stream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The port was reachable. TCP would connect, then the stream just ended. I assumed a WSL2 networking quirk and switched the exporter to &lt;code&gt;127.0.0.1&lt;/code&gt;. Same error on IPv4. ClickHouse's trace table: zero rows.&lt;/p&gt;

&lt;p&gt;The answer was sitting in the SigNoz server logs the whole time, repeating every 30 seconds. This is why you read the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"failed to find or create agent" ... "cannot create agent without orgId"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SigNoz's collector pulls its pipeline config from the server over OpAMP, and the server won't register the collector until an organization exists. The organization gets created when you fill in the admin signup form on first load. Until you do that, the OTLP receiver never starts, and from the outside it is indistinguishable from a broken network.&lt;/p&gt;

&lt;p&gt;Seconds after I created the account, the collector logged &lt;code&gt;Starting GRPC server [::]:4317 ... Everything is ready&lt;/code&gt; and spans started flowing. Thirty minutes of debugging, resolved by a signup page.&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%2Fb816k8vvqz35mtlfwgkp.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%2Fb816k8vvqz35mtlfwgkp.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The service: 15 chunks, three spans
&lt;/h2&gt;

&lt;p&gt;The app is deliberately tiny. FastAPI, ChromaDB with 15 hardcoded chunks about coffee brewing, local MiniLM ONNX embeddings, and Groq's &lt;code&gt;llama-3.3-70b-versatile&lt;/code&gt; for answers. Auto-instrumentation for FastAPI and httpx, plus three manual spans around the pipeline stages:&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;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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embed_query&lt;/span&gt;&lt;span class="sh"&gt;"&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;embedding.model&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;all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;query_embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed_fn&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&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;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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vector_search&lt;/span&gt;&lt;span class="sh"&gt;"&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;top_k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_embeddings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query_embedding&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;n_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top_k&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;chunks_retrieved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llm_call&lt;/span&gt;&lt;span class="sh"&gt;"&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;gen_ai.request.model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GROQ_MODEL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# ... Groq call, prompt_tokens recorded from the response
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I fired 45 requests at it: 35 normal, 5 with &lt;code&gt;top_k=12&lt;/code&gt; to stress retrieval, and 5 rigged to fail with a bad API key or an injected exception.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the traces actually said
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The latency split was not where I expected.&lt;/strong&gt; Averaged over successful requests, &lt;code&gt;POST /ask&lt;/code&gt; took roughly 1.54 s server-side. &lt;code&gt;llm_call&lt;/code&gt; was 878 ms (57%), &lt;code&gt;embed_query&lt;/code&gt; was 648 ms (42%), and &lt;code&gt;vector_search&lt;/code&gt; was 3 ms (0.2%).&lt;/p&gt;

&lt;p&gt;I had assumed the LLM would swallow the whole request and everything local would be rounding error. Embedding one short sentence with a "free" local model cost nearly as much as a full round trip to a 70B model on Groq's hardware. On a memory-starved laptop, local inference is the second biggest line item in the request, and I would not have known that without the span breakdown.&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%2Fmzrlzm1tg0act9c6tjgp.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%2Fmzrlzm1tg0act9c6tjgp.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The single trace above is a good example of the shape: 1.62 s total, &lt;code&gt;llm_call&lt;/code&gt; 938.42 ms, &lt;code&gt;embed_query&lt;/code&gt; 673.48 ms. Two bars, nearly the same height, and only one of them is the model I was paying attention to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The client and the server disagreed by 2.6 seconds, and both were right.&lt;/strong&gt; My load script measured p50 at 4,214 ms. SigNoz showed the server span at p50 1,590 ms.&lt;/p&gt;

&lt;p&gt;That gap lives outside the traced service, which is the useful part: the trace draws a border around what my code is responsible for. A quick A/B nailed it. The same request took about 4.3 s via &lt;code&gt;http://localhost:8001&lt;/code&gt; and about 1.9 s via &lt;code&gt;http://127.0.0.1:8001&lt;/code&gt;. Windows resolves &lt;code&gt;localhost&lt;/code&gt; to IPv6 &lt;code&gt;::1&lt;/code&gt; first, uvicorn was listening only on IPv4, and every request paid a ~2.4 s fallback tax before a single byte reached my code. No server-side metric would ever have surfaced that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The errors looked like the failures they were.&lt;/strong&gt; The bad-API-key traces show an errored &lt;code&gt;llm_call&lt;/code&gt; span of about 587 ms, a real round trip that came back 401 Unauthorized from api.groq.com, with the message preserved verbatim in the span status. The injected exceptions error out in 2 ms, dying instantly instead of after a network hop. You can tell the two failure modes apart from their shape alone, before reading anything.&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%2Facpr8raskx78i9mtea17.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%2Facpr8raskx78i9mtea17.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One detail I only noticed while scrolling that error list: the root &lt;code&gt;POST /ask&lt;/code&gt; span for an injected-exception trace is 678.54 ms even though its &lt;code&gt;llm_call&lt;/code&gt; child is 2.74 ms. The request fails almost instantly at the LLM step and still pays the full local embedding cost first. Fail-fast at the end of a pipeline isn't fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And an honest null result.&lt;/strong&gt; Cranking &lt;code&gt;top_k&lt;/code&gt; from 3 to 12 did nothing measurable. Vector search went from 3.3 ms to 3.6 ms, and tripling the prompt (about 115 to 350 tokens) didn't move Groq's latency in any way I could distinguish from noise. A 15-document corpus can't make retrieval expensive. I'm reporting that rather than pretending I found something.&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%2Ffnipws15y1g3mflei97d.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%2Ffnipws15y1g3mflei97d.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 11.11% error rate on that overview is just my 5 rigged failures out of 45 calls, which was a small relief to see land where it should.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell myself before starting
&lt;/h2&gt;

&lt;p&gt;The trace waterfall's value on day one wasn't finding a slow function. It was accounting for 99% of server time, which meant the missing 2.6 s could only be client-side. Subtraction turned out to be the useful operation.&lt;/p&gt;

&lt;p&gt;Instrument before you optimize your assumptions. I would have gone straight at the LLM call. The data pointed at a local embedding model and a hostname.&lt;/p&gt;

&lt;p&gt;Self-hosting observability on a small machine works, but it's unforgiving about setup order. Know your WSL2 memory default, keep the distro alive, and create the admin account before you start debugging ingestion.&lt;/p&gt;

&lt;p&gt;One accidental lesson too: an early ChromaDB bug of mine dumped an entire 384-dimension embedding vector into a span's status message. Worth watching what your error paths put into telemetry.&lt;/p&gt;

&lt;p&gt;One afternoon, no cloud spend, and two of the three bugs I found were in my environment rather than my code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Setup used: SigNoz self-hosted via Foundry on Docker in WSL2, FastAPI + ChromaDB + Groq, OpenTelemetry Python SDK. Install docs: &lt;a href="https://signoz.io/docs/install/docker/" rel="noopener noreferrer"&gt;signoz.io/docs/install/docker&lt;/a&gt;. OpenTelemetry Python: &lt;a href="https://opentelemetry.io/docs/languages/python/" rel="noopener noreferrer"&gt;opentelemetry.io&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>observability</category>
      <category>opentelemetry</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
