Adding Observability to a Go App Using OpenTelemetry and SigNoz

Hey folks! 👋
Ever screamed “WHY is this app slow?!” while staring at your terminal like it betrayed you?

Yeah, we’ve all been there.
500 errors. Logs missing the real issue. Dashboards saying “everything’s fine” when your users say otherwise.

It’s not magic, it’s missing observability. So today, we’re fixing that with OpenTelemetry+ SigNoz (self-hosted).

Grab your coffee , your favorite terminal theme, and let’s go from “what just happened?” to “oh, I see exactly where it broke” all in Go.

Why Observability Now?

Let’s be honest. Logs in files and Prometheus metrics can only take you so far.

You’re probably here because:

  • You’ve had multiple outages and postmortems pointed to "lack of visibility"

  • Developers are tired of playing whack-a-mole with flaky services

  • You’re looking for an open source, production grade APM solution

Enter OpenTelemetry + SigNoz.

Meet the Heroes: OpenTelemetry and SigNoz

OpenTelemetry: The Universal Spy Kit

OpenTelemetry (or just OTel) is a CNCF project that lets you collect logs, metrics and traces from your app. It’s vendor-neutral, cloud-native, and growing like crazy.

Think of OpenTelemetry as the instrumentation toolkit. it captures data inside your app.

You install a Go SDK, sprinkle in a few lines of code, and it starts recording data like:

  • how long requests take,

  • what endpoints are hit,

  • where errors happen, and more.

Cool, right?

SigNoz: Your Observability Command Center

SigNoz is the dashboard where all your app’s secrets come together.

It’s open-source, self-hostable and built to give you a seamless experience:

  • View traces like a Jaeger

  • Plot metrics like Prometheus + Grafana

  • Explore logs like Loki

  • All-in-one, powered by ClickHouse under the hood.

Why SigNoz instead of stitching tools together?

  • No Prometheus + Grafana + Jaeger + Loki madness.

  • Works out of the box with OpenTelemetry.

  • Beautiful UI. Self-hosted or cloud — your choice.

SigNoz Architecture

At a high level, here’s how SigNoz works:

  • Collector → receives traces, metrics, logs

  • Query Service → talks to ClickHouse

  • Frontend → shows everything in a nice dashboard

You can run all of this using Docker in 5 minutes.

Let’s Build an Observable Go App

Now let’s make all this practical. We’ll build a small Go HTTP app, instrument it using OpenTelemetry, and ship data to self-hosted SigNoz. (I have created a sample GitHub repo with all the code and prompt files mentioned in this blog. Check out the repo here)

Step 1: Build a Tiny Go App

// main.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Welcome to my observable blog! 📝")
    })
    http.HandleFunc("/post", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Here's a blog post!")
    })
    log.Println("Blog running on http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

You know the drill:

go run main.go

Step 2: Add OpenTelemetry SDK

go get go.opentelemetry.io/otel
go get go.opentelemetry.io/otel/sdk
go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp

Create a new file otel.go:

package main

import (
    "context"
    "log"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    "go.opentelemetry.io/otel/sdk/resource"
    sdktrace "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
)

func InitTracer() func(context.Context) error {
    ctx := context.Background()

    exporter, err := otlptracehttp.New(ctx,
        otlptracehttp.WithInsecure(),
        otlptracehttp.WithEndpoint("localhost:4318"),
    )
    if err != nil {
        log.Fatalf("Failed to create OTLP exporter: %v", err)
    }

    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceName("go-blog"),
        )),
    )
    otel.SetTracerProvider(tp)

    return tp.Shutdown
}

Now wrap handlers in your main.go:

// main.go
package main

import (
    "context"
    "fmt"
    "log"
    "net/http"

    "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

func main() {
    shutdown := InitTracer()
    defer shutdown(context.Background())

    http.Handle("/", otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Welcome to my observable blog! 📝")
    }), "HomeHandler"))

    http.Handle("/post", otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Here's a blog post!")
    }), "PostHandler"))

    log.Println("🚀 Blog running on http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

Step 3: Self-host SigNoz Locally

git clone https://github.com/SigNoz/signoz.git && cd signoz/deploy/docker
./install.sh

After it spins up, open:
👉 http://localhost:3301

You’ll see the beautiful SigNoz dashboard.

Step 4: Explore Your Data

Visit:

Then check SigNoz → Traces.
Boom! You’ll see:

  • HomeHandler

  • PostHandler

With timing, performance and trace graphs!

What Else Can You Do with SigNoz?

If you’ve made it this far, awesome. You’ve got your Go app sending traces and metrics to SigNoz. But honestly? That’s just the beginning.

There’s so much more you can explore:

  • Add your own custom spans and really trace what matters

  • Build dashboards to keep an eye on latency or errors

  • Try setting up alerts so you know when things go sideways

  • Hook up logs (yep, log support is here too in beta!)

  • Plug in other services like Node.js, Python, Java, even mobile

  • Or deploy SigNoz on Kubernetes if you’re going full scale

Basically, if you’re into visibility, performance, or just not getting paged at 3AM with no idea what broke. SigNoz is worth diving deeper into.

Get Started

0
Subscribe to my newsletter

Read articles from Harshal Rembhotkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Harshal Rembhotkar
Harshal Rembhotkar

I do Dev, I do Ops, and I do it (most days).