Sentinel Go
An opinionated, production-ready wrapper that makes OpenTelemetry instrumentation in Go effectively “drop-in” for common libraries, starting with SQL (database/sql and sqlx).


Most Go services don’t fail because they can’t do work they fail because you can’t see what work they’re doing under load, in prod, at 2 a.m.
Sentinel-Go is a Go library that aims to remove the “optional” nature of observability by making OpenTelemetry instrumentation the default path: you keep using familiar interfaces, but you get consistent spans and metrics without having to hand-roll wrappers across every codebase.
Overview
- What it is: An opinionated OpenTelemetry wrapper for Go, designed to be a drop-in replacement for standard library usage (starting with SQL).
- Who it’s for: Backend engineers and platform teams who want consistent tracing/metrics across services with minimal integration friction.
- Primary value: Standardized telemetry with best-practice defaults (including query sanitization controls) while keeping standard interfaces intact.
At a glance
- Drop-in wrappers for:
database/sqlviagithub.com/kroma-labs/sentinel-go/sqljmoiron/sqlxviagithub.com/kroma-labs/sentinel-go/sqlx
- Focus areas:
- Trace spans following DB semantic conventions (e.g.,
db.system,db.operation) - Metrics for query latency and connection pool behavior
- Guardrails to reduce accidental leakage of sensitive query data
- Trace spans following DB semantic conventions (e.g.,
Background
OpenTelemetry is the standard for vendor-neutral telemetry, but teams repeatedly hit the same operational bottleneck: the SDK is straightforward, while instrumenting every subsystem consistently is not. SQL is a classic example teams end up with partial tracing, inconsistent attributes, missing context propagation, and “quick fixes” that leak query text into spans.
Sentinel-Go’s stance is explicit: instrumentation should be easy to adopt, hard to misconfigure, and consistent across services.
The Problem
Typical symptoms Sentinel-Go targets:
- Inconsistent telemetry: Each service (or team) wraps libraries differently, creating incompatible dashboards and traces.
- Context propagation gaps: Traces break because context isn’t passed consistently (especially around DB calls).
- Risky defaults: Query text and parameters can land in telemetry systems unexpectedly.
- High integration cost: “We’ll add OTel later” turns into “we never added OTel” because the work is repetitive and easy to deprioritize.
Constraints implied by the repo:
- Must remain compatible with standard interfaces (e.g.,
*sql.DB) to reduce migration cost. - Must provide modular adoption (import only what’s needed).
- Must include production-grade defaults rather than sample-only patterns.
The Solution
Sentinel-Go provides wrapper modules that:
- Keep the same public surface area you already use (
sql.Open-like entry points,*sql.DBreturn types). - Instrument operations with structured spans and metrics that follow semantic conventions.
- Offer functional options to control critical behavior (e.g., database system/name attributes, query recording behavior, query sanitization).
This approach aims to shift observability from an “implementation detail” into an enforced baseline.
Key Features
Core
- Drop-in SQL wrapper (
database/sql) that returns a standard*sql.DB. - Drop-in SQLX wrapper (
jmoiron/sqlx) for teams using struct scanning and sqlx APIs. - Rich telemetry
- Tracing with DB semantic attributes such as
db.systemand operation naming. - Metrics including query latency histograms and connection pool gauges.
- Tracing with DB semantic attributes such as
- Controls for query recording and sanitization
- Disable query text recording entirely.
- Provide a custom query sanitizer (or rely on built-in behavior).
Architecture
At a high level, Sentinel-Go sits between your application code and the underlying libraries, emitting OpenTelemetry signals through the configured SDK/exporters.
How data flows
- Your code executes DB operations via Sentinel-Go’s wrapper entry points.
- Sentinel-Go creates spans and records metrics around each operation.
- Signals flow through the OpenTelemetry SDK to your configured exporters (e.g., OTLP, Prometheus, vendor agents configuration depends on your application).
Tech Stack
- Language: Go
- Observability: OpenTelemetry (tracing + metrics), via wrapper modules
- Data/DB: Focused on SQL integrations (
database/sql) andsqlx - Dev tooling: Repository includes common quality automation files (e.g.,
.golangci.yaml,.pre-commit-config.yaml,.mockery.yaml) and aMakefile
Getting Started
Installation
-
Add the dependency:
go get github.com/kroma-labs/sentinel-go -
Import the module you need:
github.com/kroma-labs/sentinel-go/sqlgithub.com/kroma-labs/sentinel-go/sqlx
Configuration
Sentinel-Go exposes functional options for SQL modules:
WithDBSystem: Setsdb.system(required by OTel semantic conventions).WithDBName: Setsdb.name.WithInstanceName: Distinguishes instances (e.g., primary vs replica).WithDisableQuery: Disables recording SQL query text in spans.WithQuerySanitizer: Provide a custom sanitizer function.
Run
There is no standalone binary. This is a library you import into your service.
A typical workflow is:
go test ./...
Usage
Instrument database/sql
Use the Sentinel SQL module as a replacement for sql.Open, while keeping the returned type as a standard *sql.DB.
import (
"context"
sentinelsql "github.com/kroma-labs/sentinel-go/sql"
_ "github.com/lib/pq"
)
func main() {
ctx := context.Background()
db, err := sentinelsql.Open("postgres", "postgres://...",
sentinelsql.WithDBSystem("postgresql"),
sentinelsql.WithDBName("main_db"),
)
if err != nil {
panic(err)
}
defer db.Close()
// Use standard *sql.DB methods; context is required for trace propagation.
_, _ = db.QueryContext(ctx, "SELECT * FROM users WHERE id = $1", 123)
}
Instrument sqlx
Use the Sentinel SQLX module if you rely on sqlx helpers such as GetContext and SelectContext.
import (
"context"
sentinelsqlx "github.com/kroma-labs/sentinel-go/sqlx"
_ "github.com/lib/pq"
)
type User struct {
ID int `db:"id"`
Name string `db:"name"`
}
func main() {
ctx := context.Background()
db, err := sentinelsqlx.Open("postgres", "postgres://...",
sentinelsqlx.WithDBSystem("postgresql"),
sentinelsqlx.WithDBName("main_db"),
)
if err != nil {
panic(err)
}
defer db.Close()
var user User
_ = db.GetContext(ctx, &user, "SELECT * FROM users WHERE id = $1", 1)
}
Suggested operational patterns
-
Initialize OpenTelemetry SDK/exporters in your service startup (outside Sentinel-Go).
-
Ensure every DB call uses
context.Contextto preserve trace continuity. -
Decide your policy for query recording:
- Disable query text in spans for high-sensitivity environments.
- Use a sanitizer to reduce leakage risk while retaining diagnostic value.
hubSimilar Projects
View Allarrow_forwardGo Gin Starter
A Go (Gin) backend starter template that applies Clean Architecture conventions, PostgreSQL integration, and a practical local/dev workflow (Air hot reload + Docker Compose) to help teams ship APIs faster with consistent structure.
E Commerce Microservice
A learning-oriented, production-patterned microservices e-commerce platform in Go, featuring an API gateway, Kafka + RabbitMQ eventing, PostgreSQL replication, Redis idempotency locks.