Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions docs/CHANGELOG-native-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# O que está subindo — Native Metrics + Auto-Instrumentation (lib-observability)

> Registro vivo do que este trabalho adiciona à lib. Vira o corpo do PR único p/ develop.
> Branch: `feat/native-metrics-phase1` (base develop pós-#30). Atualizar a cada feature.
> Ref: pre-dev `docs/pre-dev/observability-metrics-standardization/` · contrato `docs/metrics-contract.md`

## Objetivo
Padronizar a emissão de métricas transversais (a lib emite por default, nome/unidade/labels iguais p/ 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).

## Não confundir
- **PR #30 (já mergeado)** = fix de span.name (route template). Pré-requisito, NÃO faz parte deste trabalho.
- **Adoção nas apps (midaz/ledger)** = outro repo, outro PR (Fase 3). Este PR é SÓ a lib.

---

## FASE 1 — Métricas nativas (✅ implementada, testada)

| Feature | Métrica | Tipo | Detalhe |
|---|---|---|---|
| T1 Contrato | — | doc | `docs/metrics-contract.md`: nomes/unidade(s)/buckets/labels permitidos×proibidos/no-op. Fundação. |
| T2 RED gRPC server | `rpc.server.duration` | Float64 Histogram (s) | hook no interceptor server existente. Labels: rpc.system=grpc, rpc.method, rpc.grpc.status_code, error.type (só !=OK), tenant.id |
| T2 RED gRPC client | `rpc.client.duration` | Float64 Histogram (s) | NOVO UnaryClientInterceptor (não existia). Labels iguais, sem tenant.id. Propaga trace. |
| T3 Runtime Go | `go.*` (memory/goroutine/gc) | contrib/runtime | opt-in via `TelemetryConfig.EnableRuntimeMetrics` (default-off). MinReadMemStats 15s. |
| T4 In-flight HTTP | `http.server.active_requests` | Int64 UpDownCounter ({request}) | inc antes / dec depois. Label http.request.method. Detecta saturação. |

Arquivos: middleware/telemetry.go, tracing/otel.go, go.mod (+contrib/instrumentation/runtime v0.69.0), 3 test files (16 testes). Verificado: go test unit PASS, vet OK, lint 0, ManualReader (emissão real), zero label proibido, no-op safe.

## DESACOPLAMENTO Fiber v3 ↔ core (✅ implementado, testado) — BREAKING

Objetivo: tirar a dependência de `github.com/gofiber/fiber/v3` do núcleo da lib para que apps ainda em **Fiber v2** possam usar TUDO menos o middleware HTTP (core `NewTelemetry`, runtime metrics, messaging, gRPC, DB/cache).

Causa raiz: `tracing/otel.go` importava `fiber/v3` só por 2 helpers HTTP. Isso contaminava o pacote `tracing` inteiro e, transitivamente, `messagingobs` (importa tracing), `runtime` e os interceptors gRPC — `go list -deps ./messagingobs` mostrava 13 deps de fiber.

### O que mudou
- **`tracing` agora é fiber-free.** Removido o import de `fiber/v3` (e `redaction`/`observability`, que só existiam por causa das 2 funções movidas).
- **Novo pacote `grpcmiddleware/`** (fiber-free): interceptors gRPC saíram de `middleware` (que importa fiber). HTTP (`WithTelemetry`/`EndTracingSpans`) fica onde estava (fiber, correto).
- **Novo pacote `telemetrycore/`** (fiber-free): coletor de métricas de sistema (singleton único), compartilhado por HTTP e gRPC — evita duas goroutines de coleta quando a app usa os dois transportes.

### Símbolos movidos (BREAKING — ajustar import path nos callers)
| Símbolo | Antes | Depois |
|---|---|---|
| `SetSpanAttributeForParam(c fiber.Ctx, ...)` | `tracing` (`.../v2/tracing`) | `middleware` (`.../v2/middleware`) |
| `ExtractHTTPContext(ctx, c fiber.Ctx)` | `tracing` | `middleware` |
| `WithTelemetryInterceptor` (gRPC) | `middleware.TelemetryMiddleware` | `grpcmiddleware.TelemetryMiddleware` |
| `EndTracingSpansInterceptor` (gRPC) | `middleware.TelemetryMiddleware` | `grpcmiddleware.TelemetryMiddleware` |
| `UnaryClientInterceptor` (gRPC) | `middleware.TelemetryMiddleware` | `grpcmiddleware.TelemetryMiddleware` |
| `ResolveTenantIDFromGRPC` | `middleware` (mantido lá tb.) | também em `grpcmiddleware` |
| `StopMetricsCollector` / `DefaultMetricsCollectionInterval` | `middleware` (mantidos p/ compat) | fonte agora em `telemetrycore` |

Novo construtor gRPC: `grpcmiddleware.NewTelemetryMiddleware(tl)` (mesma assinatura de `middleware.NewTelemetryMiddleware`).

### Fix externo pendente (midaz — outro repo, outro PR)
`midaz` `pkg/net/http/withBody.go:235` usa `SetSpanAttributeForParam` importando de `tracing`. Trocar para o pacote `middleware`:
`github.com/LerianStudio/lib-observability/v2/middleware.SetSpanAttributeForParam`.
(Apps que consomem os interceptors gRPC via `middleware` também precisam trocar para `grpcmiddleware`.)

### Verificação (`go list -deps`, deps de gofiber)
| Pacote | Antes | Depois |
|---|---|---|
| `tracing` | 13 | **0** |
| `messagingobs` | 13 | **0** |
| `runtime` | 0 | 0 |
| `grpcmiddleware` (gRPC) | (era `middleware`=13) | **0** |
| `telemetrycore` | — | **0** |
| `middleware` (HTTP `WithTelemetry`) | 13 | 13 (correto, inalterado) |

Comportamento 100% preservado (só MOVE código; nenhuma lógica de métrica/telemetria alterada). `go test -tags=unit ./...` PASS em todos os pacotes; golangci-lint (wsl_v5) 0 issues. Core OTel mantido em v1.44.0.

## FASE 2 — Wrappers de auto-instrumentação (a implementar)

| Feature | Métrica | Helper | Cobre |
|---|---|---|---|
| SQL | `db.client.operation.duration` (s) | `InstrumentSQLDB(*sql.DB)` (otelsql v0.43.0) | Postgres + MySQL/MariaDB (database/sql) |
| Cache | `db.client.operation.duration` (s) | `WrapRedis(client)` (redisotel v9.17.2) | Redis + Valkey (mesmo driver go-redis) |
| ~~Doc-DB (Mongo)~~ | — | — | **ADIADO** — otelmongo v2 sem release oficial (só pseudo-version que arrastaria otel core >v1.44.0); v1 deprecated. Entra quando v2 for tagueado. Ver BACKLOG. |
| Mensageria | `messaging.client.operation.duration` / `messaging.process.duration` (s) | InstrumentPublish/Consume (hand-roll s/ helpers de propagação existentes) | RabbitMQ (contrato compartilhado c/ lib-streaming p/ RedPanda) |

Guardrails (todos): unidade s, sem query text/params/PII como label (contrato §PROIBIDO), no-op safe, instrumento 1×.
Boundary: lib expõe HELPER; conexão/dbresolver fica na app/lib-commons. Para SQL, aplicar em cada *sql.DB ANTES do dbresolver.

## FORA deste PR
- Adoção no ledger + aposentar spans manuais (Fase 3, repo midaz).
- Dashboard genérico + rollout (Fase 4).
- Business metrics (skill Ring dev-sre, frente paralela).
- IBM MQ (backlog isolado). RedPanda/Kafka (lib-streaming, repo separado).

## BACKLOG (fora deste PR, rastreado)
- **Mongo helper (`mongoobs`):** implementar quando `otelmongo v2` (`go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo`) tiver release oficial que resolva p/ otel core v1.44.x. Hoje: v2 sem tag (só pseudo-version → arrastaria core p/ pré-release, viola pin); v1 v0.69.0 existe mas deprecated + driver v1. Padrão: mirror dos outros helpers, `SetMonitor` no `*options.ClientOptions` v2. Verificado no proxy Go 2026-07-22.

## Riscos registrados
- **otelmongo v2** exige mongo-driver v2 na APP — não na lib (a lib só provê o helper). Migração do driver é Fase 3.
- **gRPC naming:** mantido experimental `rpc.server.duration`+`rpc.grpc.status_code` p/ consistir c/ span; revisar em lockstep quando semconv migrar.
57 changes: 57 additions & 0 deletions docs/metrics-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Metric Contract — lib-observability

> Fonte canônica dos nomes/unidade/buckets/labels das métricas emitidas pela lib.
> Toda métrica nativa DEVE seguir este contrato. Testes validam contra ele.
> Base: OpenTelemetry Semantic Conventions. Ver pre-dev `docs/pre-dev/observability-metrics-standardization/`.

## Princípios

1. **Unidade = segundos (`s`)** para toda duração (semconv). NUNCA milissegundos na lib.
- Leitura em ms é responsabilidade do PAINEL: no Grafana, unidade do campo = `seconds (s)` → formata "50 ms"/"1.2 s" automaticamente. Fallback em query: `... * 1000` (fator 1000, multiplica; NÃO converte o label `le` de heatmap/bucket).
- NÃO dual-emitir (ms+s) na lib. NÃO converter no collector. Compat legacy de dashboards antigos migra p/ unidade-do-painel.
2. **Instrumento criado UMA vez** na construção (nunca por request). Record é **no-op** quando o instrumento é nil (telemetria desabilitada) — chamável incondicionalmente, nunca panic, nunca afeta o request path.
3. **Só labels de baixa cardinalidade bounded.** Ver lista PROIBIDA abaixo. Cada valor distinto de um label multiplica séries.
4. **Nomes = OTel semconv estável.** Não inventar chaves; reusar `constants/opentelemetry.go`.
5. **tenant.id** auto em RED (HTTP/gRPC) via resolver existente; MANUAL em métrica de negócio.

## Buckets advisory (por sinal)

| Sinal | Buckets (segundos) |
|---|---|
| HTTP / RPC / Messaging | `0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10` |
| Database | `0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10` (mais fino no low-end) |

## Catálogo (nome / tipo / unidade / labels)

| Métrica | Tipo | Unidade | Labels permitidos | Estabilidade |
|---|---|---|---|---|
| `http.server.request.duration` | Histogram | s | http.request.method, http.response.status_code, http.route, error.type, tenant.id | STABLE (já existe) |
| `http.client.request.duration` | Histogram | s | http.request.method, http.response.status_code, server.address, error.type | STABLE (já existe) |
| `http.server.active_requests` | UpDownCounter | {request} | http.request.method, http.route (opcional) | (T4) |
| `rpc.server.duration`¹ | Histogram | s | rpc.system, rpc.method, rpc.grpc.status_code, error.type, tenant.id | (T2) |
| `rpc.client.duration`¹ | Histogram | s | rpc.system, rpc.method, rpc.grpc.status_code, error.type | (T2) |
| `db.client.operation.duration` | Histogram | s | db.system.name, db.operation.name, db.collection.name, db.namespace, error.type | STABLE (Fase 2) |
| `messaging.client.operation.duration` (produce) | Histogram | s | messaging.system, messaging.operation.name, messaging.destination.template, error.type | (Fase 2) |
| `messaging.process.duration` (consume) | Histogram | s | messaging.system, messaging.operation.name, messaging.destination.template, messaging.consumer.group.name, error.type | (Fase 2) |
| `go.*` (runtime) | Gauge/Counter/Hist | várias | (dimensões fixas do contrib/runtime) | (T3) |

¹ **Nota gRPC (validar na T2):** o train contrib atual pode emitir `rpc.server.duration` (experimental, este contrato) ou `rpc.server.call.duration` (RC, semconv). Confirmar o nome contra o pacote pinado no momento da T2 e alinhar. Manter `rpc.grpc.status_code` OU `rpc.response.status_code` conforme o que o interceptor da lib emite (hoje o span/métrica usam `rpc.grpc.status_code`, setado em `grpcmiddleware.WithTelemetryInterceptor` / `recordRPCDuration`).

## PROIBIDO como label (PII / cardinalidade ilimitada)

- query text / SQL / bind params / valores de coluna
- `db.query.text` → só em SPAN, opt-in; NUNCA em métrica
- routing key / message id / partition com id
- `url.path` com id/uuid; path resolvido concreto (span.name — raiz do problema original)
- pix key, document (cpf/cnpj), email, qualquer PII
- request/response payload

## Habilitação / no-op

- Métrica emitida quando telemetria habilitada (provider+MetricsFactory não-nil — sinal existente na lib) e o subsistema ligado.
- Toggles opt-in em `TelemetryConfig` p/ subsistemas novos (runtime, db-instrumentation), default-safe, degradam p/ no-op quando off. Nunca erro que quebre a app.

## Referências
- Padrão de implementação (template): `middleware/telemetry.go` — `newHTTPServerDurationHistogram` (:45-61), `recordHTTPServerDuration` (:386+).
- semconv: opentelemetry.io/docs/specs/semconv/{http,rpc,database,messaging}/*
- Decisões: `docs/pre-dev/observability-metrics-standardization/trd.md` (ADRs), `dependency-map.md` (versões).
10 changes: 8 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ module github.com/LerianStudio/lib-observability/v2
go 1.26.3

require (
github.com/XSAM/otelsql v0.43.0
github.com/gofiber/fiber/v3 v3.4.0
github.com/google/uuid v1.6.0
github.com/redis/go-redis/extra/redisotel/v9 v9.17.2
github.com/redis/go-redis/v9 v9.17.2
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/shopspring/decimal v1.4.0
github.com/stretchr/testify v1.11.1
go.opentelemetry.io/contrib/bridges/otelzap v0.19.0
go.opentelemetry.io/contrib/instrumentation/runtime v0.69.0
go.opentelemetry.io/otel v1.44.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.20.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.44.0
Expand All @@ -22,14 +26,15 @@ require (
go.opentelemetry.io/otel/trace v1.44.0
go.uber.org/mock v0.6.0
go.uber.org/zap v1.28.0
google.golang.org/grpc v1.81.1
google.golang.org/grpc v1.82.1
)

require (
github.com/andybalholm/brotli v1.2.2 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
Expand All @@ -41,6 +46,7 @@ require (
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/redis/go-redis/extra/rediscmd/v9 v9.17.2 // indirect
github.com/tinylib/msgp v1.6.4 // indirect
github.com/tklauser/go-sysconf v0.4.0 // indirect
github.com/tklauser/numcpus v0.12.0 // indirect
Expand All @@ -52,7 +58,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.53.0 // indirect
golang.org/x/net v0.56.0 // indirect
golang.org/x/sys v0.46.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.39.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
Expand Down
24 changes: 20 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
github.com/XSAM/otelsql v0.43.0 h1:ZIhXqRoMhILXQwBQoq/Dl6Taap/KEFQXZrWjYV1L8X8=
github.com/XSAM/otelsql v0.43.0/go.mod h1:DJBGBvbtwf1OCBYRTjpRFxOqi6ONpdfb+htr4ncRWuw=
github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM=
github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down Expand Up @@ -44,6 +52,12 @@ github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/extra/rediscmd/v9 v9.17.2 h1:KYWnHK9pwzOUo3sNJlNmzRwZ5mw7opugn8njtGThKNg=
github.com/redis/go-redis/extra/rediscmd/v9 v9.17.2/go.mod h1:wsfMQVl/GFYD9Gx/tlxurlTtvHkZRAt8j1qi27eIlTk=
github.com/redis/go-redis/extra/redisotel/v9 v9.17.2 h1:wthFPRW3Y50CknMrjjJoYwXUFR4U7hMVJCMeLzDI8s4=
github.com/redis/go-redis/extra/redisotel/v9 v9.17.2/go.mod h1:iqfQX7U2o8MWSl8W+Ah8KqbQyi/UoR/MQNgvaUyA1wc=
github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI=
github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/shamaton/msgpack/v3 v3.1.2 h1:d5gWAIyMU4M0WgDjz6IFSCuXJUA2dFwRHBpDclE8CLw=
Expand Down Expand Up @@ -74,6 +88,8 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/bridges/otelzap v0.19.0 h1:48Eq3xxFx2KlL/tF7lnl42kKJBDlhNTLRzv0h154JnM=
go.opentelemetry.io/contrib/bridges/otelzap v0.19.0/go.mod h1:cQbV77F0u6HmtZPiQD9oxp2esaOEb4uLqIta6OFIKOk=
go.opentelemetry.io/contrib/instrumentation/runtime v0.69.0 h1:MtkMsuRo3zEXTTMALfyrszwCDZTkB6wolyPjbwFAdq0=
go.opentelemetry.io/contrib/instrumentation/runtime v0.69.0/go.mod h1:FYTxnpsm+UPD0erZNq20GvnM8T2YQHiHtT2vokdpoac=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.20.0 h1:rydZ9sxbcFdm/oWrVyfLTjHIygMgv0bEeMd+3B/BvoM=
Expand Down Expand Up @@ -120,8 +136,8 @@ golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
Expand All @@ -130,8 +146,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE=
google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
Loading
Loading