<?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: Anand Mishra</title>
    <description>The latest articles on DEV Community by Anand Mishra (@godl_am).</description>
    <link>https://dev.to/godl_am</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%2F4035632%2F05f17c96-cccb-4039-b8d2-b0d391b07b07.jpg</url>
      <title>DEV Community: Anand Mishra</title>
      <link>https://dev.to/godl_am</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/godl_am"/>
    <language>en</language>
    <item>
      <title>I put OpenTelemetry + SigNoz on my 6-microservice Spring Boot app — and my 6GB laptop nearly gave up</title>
      <dc:creator>Anand Mishra</dc:creator>
      <pubDate>Sat, 18 Jul 2026 17:45:17 +0000</pubDate>
      <link>https://dev.to/godl_am/i-put-opentelemetry-signoz-on-my-6-microservice-spring-boot-app-and-my-6gb-laptop-nearly-gave-up-2edk</link>
      <guid>https://dev.to/godl_am/i-put-opentelemetry-signoz-on-my-6-microservice-spring-boot-app-and-my-6gb-laptop-nearly-gave-up-2edk</guid>
      <description>&lt;p&gt;A single click in my app — "create ticket" — quietly touches four services and crosses a Kafka topic before anything reaches the user's inbox. When that click got slow, I had no idea which hop to blame. Running &lt;code&gt;docker logs&lt;/code&gt; on six containers, one at a time, is not observability. It's guessing with extra steps.&lt;/p&gt;

&lt;p&gt;So over one long weekend I finally fixed it: I added real distributed tracing to my microservices with &lt;strong&gt;SigNoz&lt;/strong&gt; and &lt;strong&gt;OpenTelemetry&lt;/strong&gt; — without touching a single line of my application code. Here's exactly how it went, including the part where my laptop tapped out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The app: six services, zero visibility
&lt;/h2&gt;

&lt;p&gt;The project is a side build of mine called &lt;strong&gt;TicketFlow&lt;/strong&gt; — a small support-ticket system, but structured the "real" way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an &lt;strong&gt;API Gateway&lt;/strong&gt; (JWT auth + routing)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eureka&lt;/strong&gt; for service discovery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth&lt;/strong&gt;, &lt;strong&gt;User&lt;/strong&gt;, and &lt;strong&gt;Ticket&lt;/strong&gt; services, each with its own Postgres database&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;Notification&lt;/strong&gt; service that emails users&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;Angular 17&lt;/strong&gt; frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kafka&lt;/strong&gt; connecting the ticket flow to notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It looks clean in a diagram. But the "create ticket" request travels Gateway → Ticket service → Kafka → Notification service, and I had no way to actually &lt;em&gt;see&lt;/em&gt; that journey. If it took four seconds, I couldn't tell you where those seconds went.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the OpenTelemetry Java agent
&lt;/h2&gt;

&lt;p&gt;The thing that sold me was the &lt;strong&gt;OpenTelemetry Java agent&lt;/strong&gt;. You attach one &lt;code&gt;.jar&lt;/code&gt; with &lt;code&gt;-javaagent&lt;/code&gt;, and it auto-instruments Spring MVC, Spring Cloud Gateway, JDBC (Postgres), and — the part I cared about most — &lt;strong&gt;Kafka producers and consumers&lt;/strong&gt;. No SDK wiring in every service, no annotations. For six services, that's the difference between an evening and a week.&lt;/p&gt;

&lt;p&gt;SigNoz is the backend that receives it all and lets you look at your traces, metrics, and logs in one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosting SigNoz (in WSL, the right way)
&lt;/h2&gt;

&lt;p&gt;I'm on Windows, so everything runs in &lt;strong&gt;WSL2 (Ubuntu)&lt;/strong&gt;. First lesson, learned the annoying way: &lt;strong&gt;run Docker Engine &lt;em&gt;inside&lt;/em&gt; WSL, not Docker Desktop.&lt;/strong&gt; SigNoz's ClickHouse Keeper doesn't play nice with the Desktop backend on Windows.&lt;/p&gt;

&lt;p&gt;Second lesson: the old &lt;code&gt;install.sh&lt;/code&gt; most tutorials mention is deprecated now. The current self-host path is &lt;strong&gt;Foundry&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;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://signoz.io/foundry.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tiny &lt;code&gt;casting.yaml&lt;/code&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;Then:&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;A few minutes of image pulls later, SigNoz was live on &lt;code&gt;http://localhost:8080&lt;/code&gt;, with its collector listening on &lt;code&gt;:4317&lt;/code&gt;.&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%2Fmtwitlz144istg7anc24.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%2Fmtwitlz144istg7anc24.png" alt=" " width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;SigNoz up and running — logs, traces, and metrics ingestion all active.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Instrumenting all six services with zero code changes
&lt;/h2&gt;

&lt;p&gt;Because my services run as containers, I didn't open a single Java file. I downloaded the agent once into the project:&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; otel
wget &lt;span class="nt"&gt;-O&lt;/span&gt; otel/opentelemetry-javaagent.jar &lt;span class="se"&gt;\&lt;/span&gt;
  https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in &lt;code&gt;docker-compose.yml&lt;/code&gt;, I merged this into each Java service's existing &lt;code&gt;environment:&lt;/code&gt; block, changing &lt;code&gt;OTEL_SERVICE_NAME&lt;/code&gt; for each one:&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;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# ...my existing env vars...&lt;/span&gt;
      &lt;span class="na"&gt;JAVA_TOOL_OPTIONS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-javaagent:/otel/opentelemetry-javaagent.jar"&lt;/span&gt;
      &lt;span class="na"&gt;OTEL_SERVICE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ticket-service"&lt;/span&gt;
      &lt;span class="na"&gt;OTEL_EXPORTER_OTLP_ENDPOINT&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://host.docker.internal:4317"&lt;/span&gt;
      &lt;span class="na"&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grpc"&lt;/span&gt;
      &lt;span class="na"&gt;OTEL_LOGS_EXPORTER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;otlp"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./otel/opentelemetry-javaagent.jar:/otel/opentelemetry-javaagent.jar&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:host-gateway"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;extra_hosts&lt;/code&gt; line is the bit that trips people up: my app containers sit on their own Docker network, but SigNoz's collector is published on the host at &lt;code&gt;:4317&lt;/code&gt;. &lt;code&gt;host.docker.internal:host-gateway&lt;/code&gt; is how a WSL container reaches back to the host.&lt;/p&gt;

&lt;p&gt;One conflict I hit immediately: my API Gateway published host port &lt;code&gt;8080&lt;/code&gt; — the exact port SigNoz's UI uses. They can't both bind it, so the gateway refused to start. One-line fix: map the gateway to &lt;code&gt;8090:8080&lt;/code&gt; instead. Internal routing (Angular → gateway over the Docker network) uses container names, so nothing else broke — I just hit the gateway at &lt;code&gt;localhost:8090&lt;/code&gt; after that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part where my laptop said no
&lt;/h2&gt;

&lt;p&gt;First &lt;code&gt;docker compose up --build&lt;/code&gt;, and the Angular build died on a TypeScript error — &lt;code&gt;Cannot find name 'BuiltinIteratorReturn'&lt;/code&gt;, a newer &lt;code&gt;@types/node&lt;/code&gt; wanting a newer TypeScript than my project pins. A failed build aborts the whole &lt;code&gt;up&lt;/code&gt;, so &lt;em&gt;nothing&lt;/em&gt; started. I pinned &lt;code&gt;@types/node&lt;/code&gt; and set &lt;code&gt;skipLibCheck: true&lt;/code&gt; to get moving.&lt;/p&gt;

&lt;p&gt;Then the real wall. I tried to boot all nine JVMs at once &lt;strong&gt;plus&lt;/strong&gt; SigNoz's ClickHouse stack — on a laptop with about &lt;strong&gt;6 GB of RAM total&lt;/strong&gt;, where WSL was quietly capped at ~2.8 GB. The VM started swapping, then swap-died, and froze so hard the terminal stopped responding.&lt;/p&gt;

&lt;p&gt;Not gonna lie — terminal frozen, laptop fans screaming, well past midnight — I seriously thought about giving up and going back to grepping logs the old way. But quitting over a memory setting felt too dumb, so I pushed on.&lt;/p&gt;

&lt;p&gt;The fix was three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Heap caps&lt;/strong&gt; — &lt;code&gt;-Xmx256m&lt;/code&gt; on each app's &lt;code&gt;JAVA_TOOL_OPTIONS&lt;/code&gt;, plus modest &lt;code&gt;KAFKA_HEAP_OPTS&lt;/code&gt; for Kafka and Zookeeper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More room for WSL&lt;/strong&gt; — a &lt;code&gt;C:\Users\&amp;lt;me&amp;gt;\.wslconfig&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;   &lt;span class="nn"&gt;[wsl2]&lt;/span&gt;
   &lt;span class="py"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4GB&lt;/span&gt;
   &lt;span class="py"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;6GB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then &lt;code&gt;wsl --shutdown&lt;/code&gt; to apply it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A staggered bring-up&lt;/strong&gt; instead of a boot storm:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; postgres zookeeper kafka
   docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; eureka-server          &lt;span class="c"&gt;# wait ~30s until healthy&lt;/span&gt;
   docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; auth-service user-service ticket-service notification-service api-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, all five Spring Boot apps started, registered with Eureka, and the gateway reported &lt;code&gt;{"status":"UP"}&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The payoff: watching a request cross Kafka
&lt;/h2&gt;

&lt;p&gt;I generated some real traffic through the gateway — register, login, create a ticket — and opened SigNoz. All five services showed up right away.&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%2Fk1xno5t35unclu9jr3u7.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%2Fk1xno5t35unclu9jr3u7.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;All five services reporting in. Notice the multi-second P99 latency — that was my first hint the environment, not the code, was the bottleneck.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then came the moment that made the whole exercise worth it — the trace for one create-ticket call.&lt;/p&gt;

&lt;p&gt;I'd sketched this exact request flow on paper more times than I can count. Seeing it actually render — every hop in order, with real timings attached — was oddly satisfying, like the whiteboard diagram had finally come to life.&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%2F1c6k1j2v5pgxgilwrzu6.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%2F1c6k1j2v5pgxgilwrzu6.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;One trace, ten spans: api-gateway → ticket-service → &lt;code&gt;INSERT ticket_db&lt;/code&gt; → &lt;code&gt;ticket-events publish&lt;/code&gt; (Kafka producer) → &lt;code&gt;ticket-events process&lt;/code&gt; on notification-service (Kafka consumer).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the feature I like most in SigNoz: &lt;strong&gt;the trace context propagates across the Kafka topic.&lt;/strong&gt; The producer span in the ticket service and the consumer span in the notification service are stitched into the &lt;em&gt;same&lt;/em&gt; trace — even though those two services never call each other and only meet through a topic named &lt;code&gt;ticket-events&lt;/code&gt;. Two fully decoupled services, one continuous story. And the Postgres &lt;code&gt;INSERT&lt;/code&gt; and &lt;code&gt;SELECT&lt;/code&gt; calls sit right there as child spans, so I can see the DB time too.&lt;/p&gt;

&lt;p&gt;There was a bonus insight hiding in the timings. The API call itself returned in about &lt;strong&gt;3.6 seconds&lt;/strong&gt; — but the trace didn't stop there. The notification service picked up the Kafka event and kept working for another &lt;strong&gt;~10 seconds&lt;/strong&gt;, long after the user already had their response. Because SigNoz keeps both halves in a single trace, I could actually &lt;em&gt;see&lt;/em&gt; that asynchronous background work happening — something that's completely invisible if you only stare at the API's response time. That's the whole promise of Kafka — fire an event and move on — finally made visible.&lt;/p&gt;

&lt;p&gt;It flagged failures cleanly too. A mistyped login showed up as its own trace, marked &lt;code&gt;401&lt;/code&gt;, with the error landing exactly on the auth service's Postgres lookup — no log-diving required.&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%2Fw18cw5hf5d76yau3188f.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%2Fw18cw5hf5d76yau3188f.png" alt=" " width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A failed login, caught as a 401 — SigNoz pointed straight at where it broke.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the traces actually taught me
&lt;/h2&gt;

&lt;p&gt;Here's the twist. My requests were &lt;em&gt;slow&lt;/em&gt; — multi-second spans everywhere. My first instinct was "my code is doing something dumb." But the traces told a different story: the time wasn't in my business logic. It was the environment — memory pressure and swapping dragging everything down. On a properly-resourced box, those same spans would collapse to milliseconds.&lt;/p&gt;

&lt;p&gt;That's the real lesson of distributed tracing: &lt;strong&gt;it doesn't lie about where time goes.&lt;/strong&gt; Without it, I'd have spent an evening "optimizing" ticket-service code that was never the problem. With it, one look at the waterfall pointed straight at the actual bottleneck.&lt;/p&gt;

&lt;p&gt;A few things I'm taking away:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;OpenTelemetry Java agent&lt;/strong&gt; is the fastest way to instrument an existing Spring Boot fleet — Spring, JDBC, and Kafka, all with zero code changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kafka context propagation&lt;/strong&gt; turns a pile of decoupled services back into one readable request flow. In an event-driven system, this alone justifies tracing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosting SigNoz is realistic&lt;/strong&gt;, but budget your RAM honestly. On a small machine, cap the JVM heaps and give WSL room, or it &lt;em&gt;will&lt;/em&gt; swap-die.&lt;/li&gt;
&lt;li&gt;Observability is a mindset shift: stop guessing where the time went, and go look.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building anything where more than two services talk to each other, this is worth an afternoon. Mine fought back a little because of the hardware — but watching that one trace stitch itself across Kafka made it completely worth it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Spring Boot, Kafka, Angular, PostgreSQL, OpenTelemetry, and SigNoz.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>observability</category>
      <category>microservices</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
