Skip to content

feat(metrics): native RED/runtime metrics + DB/cache/queue instrumentation helpers#36

Merged
gauchito91 merged 3 commits into
developfrom
feat/native-metrics-phase1
Jul 23, 2026
Merged

feat(metrics): native RED/runtime metrics + DB/cache/queue instrumentation helpers#36
gauchito91 merged 3 commits into
developfrom
feat/native-metrics-phase1

Conversation

@gauchito91

Copy link
Copy Markdown
Contributor

Objetivo

Padronizar a emissão de métricas transversais (a lib emite por default, com nome/unidade/labels iguais em todo serviço) e oferecer helpers de auto-instrumentação de DB/cache/fila — para acabar com a bagunça de métricas por-app e aposentar spans manuais de infra (origem de ~27k séries de alta cardinalidade identificadas na migração pro Grafana Cloud).

Retrocompatível: nada muda até a app adotar. Runtime metrics é opt-in.

Métricas nativas (automáticas)

Métrica Tipo Mede
rpc.server.duration / rpc.client.duration Histogram (s) latência gRPC entrada/saída (client interceptor é novo)
http.server.active_requests UpDownCounter requests HTTP em andamento (saturação)
go.* (runtime) contrib/runtime goroutines/heap/GC — leak antes do OOM (opt-in EnableRuntimeMetrics)

Helpers de auto-instrumentação (lib expõe helper; app cria o client)

Pacote Cobre Métrica
sqlobs PostgreSQL + MySQL/MariaDB (otelsql) db.client.operation.duration
redisobs Redis + Valkey (redisotel, mesmo driver) db.client.operation.duration
messagingobs RabbitMQ (hand-roll, sem dep amqp na lib) messaging.client.operation.duration / messaging.process.duration

Para SQL com dbresolver: instrumentar cada *sql.DB antes do resolver (documentado).

Guardrails

  • Unidade segundos (semconv); ms é formatação no painel Grafana, sem dual-emit.
  • Zero PII / alta cardinalidade como label: query text/params/keys/routing key/message id NUNCA viram label — coberto por testes dedicados (com dados sensíveis fake).
  • Instrumentos criados 1×; todos no-op safe quando telemetria desligada.
  • Contrato canônico em docs/metrics-contract.md.

Fora deste PR

  • MongoDB: adiado — otelmongo v2 sem release oficial (arrastaria otel core acima de v1.44.0); v1 deprecated. Backlog em docs/CHANGELOG-native-metrics.md.
  • RedPanda/Kafka: contrato de mensageria definido; implementação na lib-streaming.
  • Adoção nas apps (ledger): outro repo/PR — onde a redução de cardinalidade se materializa.
  • Docs de pre-dev: branch separada.

Testes

34 testes novos, todos passando (go test -tags=unit ./... — 13 pacotes OK), incluindo anti-PII e no-op. golangci-lint 0 issues. OTel core mantido em v1.44.0.

Deps

XSAM/otelsql v0.43.0, redis/go-redis/extra/redisotel/v9 v9.17.2, contrib/instrumentation/runtime v0.69.0 — todas resolvem p/ otel core v1.44.0.

🤖 Generated with Claude Code

…ation helpers

Standardize transversal metrics emission and add thin auto-instrumentation
helpers so services stop hand-writing infra spans and stop inventing per-app
metric names.

Native metrics (automatic when middleware registered + telemetry on):
- rpc.server.duration / rpc.client.duration (gRPC RED; client interceptor is new)
- http.server.active_requests (in-flight UpDownCounter, saturation signal)
- Go runtime metrics (go.*) via contrib/runtime, opt-in EnableRuntimeMetrics

Auto-instrumentation helpers (lib exposes helper; app owns the connection):
- sqlobs: db.client.operation.duration for PostgreSQL + MySQL/MariaDB (otelsql).
  Query text disabled (DisableQuery); instrument each *sql.DB before dbresolver.
- redisobs: same metric for Redis + Valkey (redisotel; WithDBStatement(false)).
- messagingobs: messaging.client.operation.duration / messaging.process.duration
  for RabbitMQ, hand-rolled over existing queue trace-context helpers (no amqp
  dep in the lib; destination.template only, never routing key / message id).

All instruments built once, no-op safe when telemetry disabled, unit=seconds,
low-cardinality labels only (no query text / keys / IDs / PII — covered by tests).
Metric contract documented in docs/metrics-contract.md.

Mongo (otelmongo) deferred: v2 has no tagged release (would drag otel core off
v1.44.0), v1 is deprecated. Tracked in docs/CHANGELOG-native-metrics.md backlog.

Deps: XSAM/otelsql v0.43.0, redisotel/v9 v9.17.2, contrib/instrumentation/runtime
v0.69.0 — all resolve to otel core v1.44.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
X-Lerian-Ref: 0x1
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7d25dac8-c4a8-47a6-9371-edbf1b16d948

📥 Commits

Reviewing files that changed from the base of the PR and between d9755d0 and 6b544a2.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • docs/metrics-contract.md
  • go.mod
  • sqlobs/sqlobs.go

📝 Walkthrough

Walkthrough

Changes

Observability instrumentation

Layer / File(s) Summary
Metric contracts and dependencies
docs/*, go.mod
Documents metric units, labels, buckets, guardrails, scope, and adds instrumentation dependencies.
HTTP active-request metrics
middleware/telemetry.go, middleware/telemetry_active_requests_test.go
Adds http.server.active_requests tracking across the Fiber handler chain with method labels and telemetry gating.
gRPC server and client telemetry
grpcmiddleware/*
Adds duration histograms, trace propagation, request and tenant resolution, error labels, span lifecycle coordination, and tests.
Fiber and telemetry-core decoupling
middleware/*, tracing/otel.go, telemetrycore/*
Moves Fiber tracing helpers into middleware and centralizes restartable system-metrics collection in telemetrycore.
Opt-in runtime metrics
tracing/otel.go, tracing/runtime_metrics_test.go
Adds optional Go runtime instrumentation after meter-provider initialization with safe disabled and failure paths.
SQL instrumentation wrappers
sqlobs/*
Adds caller-owned SQL instrumentation, system and pool-role labels, query-text suppression, and optional pool metrics.
Redis instrumentation helper
redisobs/*
Adds go-redis tracing and metrics instrumentation with command-text suppression, provider options, and nil-safe behavior.
RabbitMQ messaging instrumentation
messagingobs/*
Adds producer and consumer helpers for trace-header propagation, bounded attributes, duration metrics, error labels, and no-op telemetry.

Sequence Diagram(s)

sequenceDiagram
  participant Publisher
  participant RabbitMQHeaders
  participant Consumer
  Publisher->>Publisher: Start producer span
  Publisher->>RabbitMQHeaders: Inject trace context
  RabbitMQHeaders->>Consumer: Deliver inbound headers
  Consumer->>Consumer: Extract trace context and start consumer span
  Consumer->>Consumer: Record processing duration and end span
Loading
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/native-metrics-phase1

Comment @coderabbitai help to get the list of available commands.

@lerian-studio lerian-studio added size/XL PR changes ≥ 1000 lines — consider splitting docs Documentation, llms.txt and markdown content middleware HTTP/gRPC observability middleware tracing Distributed tracing tests Unit, integration and end-to-end tests deps Go module dependencies (usually opened by Dependabot) labels Jul 23, 2026
@lerian-studio

lerian-studio commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🔒 Security Scan Results — lib-observability

✅ PR Mergeable — no blocking findings

Stage Status Blocking?
Filesystem Scan ✅ Clean
Docker Image Scan ➖ Skipped
Docker Hub Health Score ➖ Skipped
Pre-release Version Check ✅ Clean

Trivy

Filesystem Scan

✅ No vulnerabilities or secrets found.


Pre-release Version Check

✅ No unstable version pins found.


🔍 View full scan logs

@lerian-studio

lerian-studio commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Validation Summary

✅ PR Mergeable — no blocking failures

Check Status Blocking
Source Branch ✅ success yes
PR Title ✅ success yes
PR Description ✅ success yes
PR Size ✅ success no
Auto Labels ✅ success no
PR Metadata ✅ success no

🔍 View workflow run

@lerian-studio

lerian-studio commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

📊 Unit Test Coverage Report: lib-observability

Metric Value
Overall Coverage 84.8% ✅ PASS
Threshold 80%

Coverage by Package

Package Coverage
github.com/LerianStudio/lib-observability/v2/assert 97.9%
github.com/LerianStudio/lib-observability/v2/constants 83.3%
github.com/LerianStudio/lib-observability/v2/grpcmiddleware 79.0%
github.com/LerianStudio/lib-observability/v2/log 94.9%
github.com/LerianStudio/lib-observability/v2/messagingobs 89.4%
github.com/LerianStudio/lib-observability/v2/metrics 91.4%
github.com/LerianStudio/lib-observability/v2/middleware 72.6%
github.com/LerianStudio/lib-observability/v2/redaction 95.8%
github.com/LerianStudio/lib-observability/v2/redisobs 63.1%
github.com/LerianStudio/lib-observability/v2/runtime 80.4%
github.com/LerianStudio/lib-observability/v2/sqlobs 64.2%
github.com/LerianStudio/lib-observability/v2/telemetrycore 84.2%
github.com/LerianStudio/lib-observability/v2/tracing 87.2%
github.com/LerianStudio/lib-observability/v2/zap 96.0%
github.com/LerianStudio/lib-observability/v2 91.5%

Generated by Go PR Analysis workflow

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
middleware/telemetry.go (1)

247-250: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the repeated telemetry-bootstrap resolution into a helper.

The bootstrapTelemetry := tl; if bootstrapTelemetry == nil && tm != nil { bootstrapTelemetry = tm.Telemetry } snippet is duplicated identically across WithTelemetry, WithTelemetryInterceptor, and UnaryClientInterceptor, all touched by this PR. A small shared helper would remove the triplication and keep the three construction-time gates from silently drifting apart.

♻️ Proposed refactor
+func resolveBootstrapTelemetry(tl *tracing.Telemetry, tm *TelemetryMiddleware) *tracing.Telemetry {
+	if tl != nil {
+		return tl
+	}
+	if tm != nil {
+		return tm.Telemetry
+	}
+	return nil
+}
+
 func (tm *TelemetryMiddleware) WithTelemetry(tl *tracing.Telemetry, excludedRoutes ...string) fiber.Handler {
-	bootstrapTelemetry := tl
-	if bootstrapTelemetry == nil && tm != nil {
-		bootstrapTelemetry = tm.Telemetry
-	}
+	bootstrapTelemetry := resolveBootstrapTelemetry(tl, tm)

(apply the same substitution in WithTelemetryInterceptor and UnaryClientInterceptor)

Also applies to: 606-609, 809-812

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@middleware/telemetry.go` around lines 247 - 250, Extract the duplicated
bootstrap telemetry resolution into a shared helper, preserving the precedence
of the explicit `tl` value and falling back to `tm.Telemetry` only when needed
and `tm` is non-nil. Replace the inline logic in `WithTelemetry`,
`WithTelemetryInterceptor`, and `UnaryClientInterceptor` with this helper so all
three construction-time gates use the same behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/metrics-contract.md`:
- Line 38: Update the gRPC naming footnote in docs/metrics-contract.md to
reference the function or method containing the rpc.grpc.status_code span
attribute assignment instead of the stale telemetry.go:549 line reference. Keep
the existing metric-name guidance unchanged.

In `@sqlobs/sqlobs.go`:
- Around line 180-218: Update the documentation for InstrumentDB to explicitly
state that it returns a fresh *sql.DB with a separate connection pool, and
instruct callers to close the original handle and reapply SetMaxOpenConns,
SetMaxIdleConns, and SetConnMaxLifetime settings to the returned handle.

---

Outside diff comments:
In `@middleware/telemetry.go`:
- Around line 247-250: Extract the duplicated bootstrap telemetry resolution
into a shared helper, preserving the precedence of the explicit `tl` value and
falling back to `tm.Telemetry` only when needed and `tm` is non-nil. Replace the
inline logic in `WithTelemetry`, `WithTelemetryInterceptor`, and
`UnaryClientInterceptor` with this helper so all three construction-time gates
use the same behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: aecfec07-776c-4652-999e-f81d560364d1

📥 Commits

Reviewing files that changed from the base of the PR and between f1ec77b and 3d29125.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (17)
  • docs/CHANGELOG-native-metrics.md
  • docs/metrics-contract.md
  • go.mod
  • messagingobs/doc.go
  • messagingobs/messagingobs.go
  • messagingobs/messagingobs_test.go
  • middleware/telemetry.go
  • middleware/telemetry_active_requests_test.go
  • middleware/telemetry_grpc_metrics_test.go
  • redisobs/doc.go
  • redisobs/redisobs.go
  • redisobs/redisobs_test.go
  • sqlobs/doc.go
  • sqlobs/sqlobs.go
  • sqlobs/sqlobs_test.go
  • tracing/otel.go
  • tracing/runtime_metrics_test.go

Comment thread docs/metrics-contract.md Outdated
Comment thread sqlobs/sqlobs.go
… collector

Move the Fiber-dependent code out of the library core so apps still on
Fiber v2 can consume everything except the HTTP middleware (core
NewTelemetry, runtime metrics, messaging, gRPC interceptors, DB/cache
helpers). Pure code move — no metric/telemetry logic changed.

Root cause: tracing/otel.go imported gofiber/fiber/v3 only for 2 HTTP
helpers, which transitively dragged fiber into tracing, messagingobs,
runtime and the gRPC interceptors (go list -deps ./messagingobs showed 13
fiber deps).

Changes:
- tracing is now fiber-free (removed fiber/v3 import).
- SetSpanAttributeForParam / ExtractHTTPContext moved tracing -> middleware
  (new middleware/http_trace.go).
- gRPC interceptors moved to new fiber-free package grpcmiddleware/
  (WithTelemetryInterceptor, EndTracingSpansInterceptor, UnaryClientInterceptor).
- System-metrics collector moved to new fiber-free package telemetrycore/
  (single shared singleton for HTTP + gRPC).
- HTTP middleware (WithTelemetry, EndTracingSpans) stays in middleware,
  still Fiber v3 — the only package that legitimately needs it.

go list -deps gofiber count: tracing 13->0, messagingobs 13->0,
grpcmiddleware 0, telemetrycore 0; middleware stays 13 (correct).

BREAKING CHANGE: SetSpanAttributeForParam and ExtractHTTPContext move from
package tracing to package middleware; the gRPC interceptors move from
middleware.TelemetryMiddleware to grpcmiddleware.TelemetryMiddleware
(grpcmiddleware.NewTelemetryMiddleware). Consumers must update import paths
(midaz fix tracked in docs/CHANGELOG-native-metrics.md, separate repo/PR).

All tests pass (go test -tags=unit ./...); golangci-lint 0 issues; OTel
core unchanged at v1.44.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
X-Lerian-Ref: 0x1

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/CHANGELOG-native-metrics.md (1)

69-80: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the Phase 2 status to match the shipped implementation.

This section says SQL, Redis, and RabbitMQ instrumentation is “a implementar,” but the PR objectives and stack scope state these helpers are added in this PR. Marking them as pending makes the changelog misleading; either document them as implemented or explicitly exclude them from this release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/CHANGELOG-native-metrics.md` around lines 69 - 80, Update the Phase 2
section in docs/CHANGELOG-native-metrics.md to reflect that the SQL, Cache, and
Mensageria helpers are implemented and shipped in this release, rather than “a
implementar”; keep the deferred Mongo status unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@grpcmiddleware/telemetry.go`:
- Line 30: Update the google.golang.org/grpc dependency from v1.81.1 to v1.82.1
or newer in go.mod, then regenerate go.sum to match the resolved module version
and checksums.

---

Outside diff comments:
In `@docs/CHANGELOG-native-metrics.md`:
- Around line 69-80: Update the Phase 2 section in
docs/CHANGELOG-native-metrics.md to reflect that the SQL, Cache, and Mensageria
helpers are implemented and shipped in this release, rather than “a
implementar”; keep the deferred Mongo status unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 248e9ad8-9f01-4cf2-ae3e-5f63ceb5fe24

📥 Commits

Reviewing files that changed from the base of the PR and between 3d29125 and d9755d0.

📒 Files selected for processing (13)
  • docs/CHANGELOG-native-metrics.md
  • grpcmiddleware/harness_test.go
  • grpcmiddleware/telemetry.go
  • grpcmiddleware/telemetry_grpc_metrics_test.go
  • grpcmiddleware/telemetry_test.go
  • middleware/helpers.go
  • middleware/http_trace.go
  • middleware/metrics.go
  • middleware/telemetry.go
  • middleware/telemetry_test.go
  • telemetrycore/metrics_collector.go
  • telemetrycore/metrics_collector_test.go
  • tracing/otel.go
💤 Files with no reviewable changes (2)
  • middleware/helpers.go
  • tracing/otel.go

Comment thread grpcmiddleware/telemetry.go
Address CodeRabbit review on PR #36:
- security(CRITICAL): bump google.golang.org/grpc v1.81.1 -> v1.82.1
  (GHSA-hrxh-6v49-42gf, affects <1.82.1). otel core unchanged at v1.44.0.
- docs(sqlobs): document that InstrumentDB returns a FRESH *sql.DB with a
  SEPARATE connection pool — caller must Close the original handle and
  re-apply pool limits (SetMaxOpenConns/SetMaxIdleConns/SetConnMaxLifetime)
  on the returned one, else two live pools hit the same DB.
- docs(metrics-contract): replace stale telemetry.go:549 line reference with
  the function name (grpcmiddleware.WithTelemetryInterceptor / recordRPCDuration)
  after the Fiber decoupling moved the gRPC code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
X-Lerian-Ref: 0x1
@gauchito91
gauchito91 merged commit 944738d into develop Jul 23, 2026
21 checks passed
@github-actions
github-actions Bot deleted the feat/native-metrics-phase1 branch July 23, 2026 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deps Go module dependencies (usually opened by Dependabot) docs Documentation, llms.txt and markdown content middleware HTTP/gRPC observability middleware size/XL PR changes ≥ 1000 lines — consider splitting tests Unit, integration and end-to-end tests tracing Distributed tracing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants