26 Commits

Author SHA1 Message Date
releaser fff76c4acc chore(release): prepare for v0.3.0 (#143)
Release / release (push) Successful in 43s
otelsetup / vulnerabilities (push) Successful in 1m40s
otelsetup / test (push) Successful in 2m29s
pre-commit / pre-commit (push) Successful in 6m17s
## [0.3.0] - 2026-05-26

### 🚀 Features

- Add eventsourced MetricsRecorder adapter for OpenTelemetry (#142)

<!-- generated by git-cliff -->

---

**Note:** Please use **Squash Merge** when merging this PR.

Reviewed-on: #143
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-05-26 18:04:49 +00:00
argoyle 7bc3101cee feat: add eventsourced MetricsRecorder adapter for OpenTelemetry (#142)
Release / release (push) Failing after 51s
otelsetup / test (push) Successful in 2m43s
otelsetup / vulnerabilities (push) Successful in 2m44s
pre-commit / pre-commit (push) Successful in 5m55s
2026-05-26 17:57:27 +00:00
releaser a8a8d53cd1 chore(release): prepare for v0.2.7 (#141)
Release / release (push) Successful in 45s
otelsetup / vulnerabilities (push) Successful in 1m44s
otelsetup / test (push) Successful in 2m32s
pre-commit / pre-commit (push) Successful in 6m25s
## [0.2.7] - 2026-05-09

### 🐛 Bug Fixes

- *(deps)* Update opentelemetry-go monorepo (#131)
- *(ci)* Use go-test-coverage binary directly to fix Gitea Actions (#134)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.90 (#133)

### ⚙️ Miscellaneous Tasks

- *(deps)* Update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.25.0 (#136)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.12.0 (#137)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.12.1 (#138)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.12.2 (#140)

<!-- generated by git-cliff -->

---

**Note:** Please use **Squash Merge** when merging this PR.

Reviewed-on: #141
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-05-09 14:24:35 +00:00
renovate 485b8434d8 chore(deps): update pre-commit hook golangci/golangci-lint to v2.12.2 (#140)
otelsetup / vulnerabilities (push) Successful in 1m46s
otelsetup / test (push) Successful in 2m44s
Release / release (push) Successful in 53s
pre-commit / pre-commit (push) Successful in 6m55s
2026-05-09 12:33:24 +00:00
renovate 9dce38187c chore(deps): update pre-commit hook golangci/golangci-lint to v2.12.1 (#138)
Release / release (push) Successful in 1m12s
otelsetup / vulnerabilities (push) Successful in 1m56s
otelsetup / test (push) Successful in 2m48s
pre-commit / pre-commit (push) Successful in 6m24s
2026-05-04 16:16:10 +00:00
renovate 33f22237dc chore(deps): update pre-commit hook golangci/golangci-lint to v2.12.0 (#137)
otelsetup / vulnerabilities (push) Successful in 1m54s
Release / release (push) Failing after 57s
otelsetup / test (push) Successful in 2m54s
pre-commit / pre-commit (push) Successful in 5m47s
2026-05-04 14:22:17 +00:00
renovate 4bbd8b3e63 chore(deps): update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.25.0 (#136)
Release / release (push) Failing after 49s
otelsetup / vulnerabilities (push) Successful in 1m44s
otelsetup / test (push) Successful in 2m36s
pre-commit / pre-commit (push) Successful in 6m12s
2026-05-03 15:43:30 +00:00
renovate ec0ea2a287 fix(deps): update module github.com/99designs/gqlgen to v0.17.90 (#133)
otelsetup / vulnerabilities (push) Successful in 2m18s
otelsetup / test (push) Successful in 3m18s
Release / release (push) Successful in 1m2s
pre-commit / pre-commit (push) Successful in 6m15s
2026-04-29 06:18:29 +00:00
argoyle dc4bc4a98c fix(ci): use go-test-coverage binary directly to fix Gitea Actions (#134)
Release / release (push) Failing after 1m4s
otelsetup / vulnerabilities (push) Successful in 2m13s
otelsetup / test (push) Successful in 3m21s
pre-commit / pre-commit (push) Successful in 6m28s
## Summary

- `vladopajic/go-test-coverage@v2` (v2.18.5+, released 2026-04-26/27) restructured its composite action to pass inputs via env-var mapping. Gitea `act_runner` doesn't expand `${{ }}` expressions inside docker-action `env:` blocks reliably, so the literal string `${{ inputs.config }}` reached the binary and broke the 'Check coverage' step.
- Replace the action with a direct `go install` + binary invocation (matching the established Frostmoln pattern).
- Use `--github-action-output` to expose `total-coverage` as a step output, replacing the manual `go tool cover -func | grep | awk` calculations.
- Baseline artifact now stores the percentage directly instead of the full coverage profile.

## Test plan

- [x] `prek run --all-files` passes
- [ ] CI passes on this PR
- [ ] After merge, baseline artifact format propagates on next push to main

Reviewed-on: #134
2026-04-29 05:44:15 +00:00
renovate e92f853311 fix(deps): update opentelemetry-go monorepo (#131)
Release / release (push) Failing after 1m4s
otelsetup / vulnerabilities (push) Successful in 1m48s
otelsetup / test (push) Successful in 2m22s
pre-commit / pre-commit (push) Successful in 6m31s
2026-04-06 10:14:40 +00:00
releaser a6660fd70d chore(release): prepare for v0.2.6 (#130)
Release / release (push) Successful in 47s
otelsetup / test (push) Successful in 2m21s
otelsetup / vulnerabilities (push) Successful in 1m42s
pre-commit / pre-commit (push) Successful in 6m10s
## [0.2.6] - 2026-03-24

### 🐛 Bug Fixes

- *(deps)* Update module github.com/99designs/gqlgen to v0.17.88 (#121)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.89 (#129)

### ⚙️ Miscellaneous Tasks

- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.2 (#119)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.3 (#123)
- *(deps)* Update pre-commit hook gitleaks/gitleaks to v8.30.1 (#125)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.4 (#127)

<!-- generated by git-cliff -->

---

**Note:** Please use **Squash Merge** when merging this PR.

Reviewed-on: #130
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-04-02 09:15:03 +00:00
renovate cbf01d4546 fix(deps): update module github.com/99designs/gqlgen to v0.17.89 (#129)
Release / release (push) Successful in 54s
otelsetup / vulnerabilities (push) Successful in 1m48s
otelsetup / test (push) Successful in 2m39s
pre-commit / pre-commit (push) Successful in 6m7s
2026-03-24 19:16:50 +00:00
renovate cfab683ab8 chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.4 (#127)
otelsetup / vulnerabilities (push) Successful in 1m38s
otelsetup / test (push) Successful in 2m16s
Release / release (push) Successful in 57s
pre-commit / pre-commit (push) Successful in 6m28s
2026-03-22 19:05:30 +00:00
renovate 4a6c014206 chore(deps): update pre-commit hook gitleaks/gitleaks to v8.30.1 (#125)
Release / release (push) Successful in 1m26s
otelsetup / vulnerabilities (push) Successful in 2m8s
otelsetup / test (push) Successful in 3m37s
pre-commit / pre-commit (push) Successful in 7m46s
2026-03-12 16:23:48 +00:00
renovate 88ae10c9d7 chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.3 (#123)
Release / release (push) Successful in 2m0s
otelsetup / vulnerabilities (push) Successful in 2m15s
otelsetup / test (push) Successful in 3m5s
pre-commit / pre-commit (push) Successful in 8m44s
2026-03-10 11:23:11 +00:00
renovate f1cfd58922 fix(deps): update module github.com/99designs/gqlgen to v0.17.88 (#121)
Release / release (push) Successful in 56s
otelsetup / vulnerabilities (push) Successful in 1m51s
otelsetup / test (push) Successful in 2m24s
pre-commit / pre-commit (push) Successful in 7m7s
2026-03-09 01:40:04 +00:00
renovate d5528d3635 chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.2 (#119)
otelsetup / vulnerabilities (push) Successful in 1m35s
otelsetup / test (push) Successful in 2m39s
Release / release (push) Successful in 1m1s
pre-commit / pre-commit (push) Successful in 6m6s
2026-03-07 22:40:37 +00:00
releaser 15cff2329e chore(release): prepare for v0.2.5 (#118)
Release / release (push) Successful in 48s
otelsetup / vulnerabilities (push) Successful in 1m49s
otelsetup / test (push) Successful in 2m16s
pre-commit / pre-commit (push) Successful in 6m14s
## [0.2.5] - 2026-03-06

### 🐛 Bug Fixes

- *(deps)* Update opentelemetry-go monorepo to v1.42.0 (#117)

<!-- generated by git-cliff -->

---

**Note:** Please use **Squash Merge** when merging this PR.

Reviewed-on: #118
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-03-06 20:36:08 +00:00
renovate 4e2f496f5d fix(deps): update opentelemetry-go monorepo to v1.42.0 (#117)
Release / release (push) Failing after 1m2s
otelsetup / test (push) Successful in 2m21s
otelsetup / vulnerabilities (push) Successful in 2m59s
pre-commit / pre-commit (push) Successful in 16m36s
2026-03-06 20:28:23 +00:00
releaser 2d55da0fb9 chore(release): prepare for v0.2.4 (#116)
otelsetup / vulnerabilities (push) Successful in 2m3s
otelsetup / test (push) Successful in 2m40s
Release / release (push) Successful in 1m11s
pre-commit / pre-commit (push) Successful in 7m42s
## [0.2.4] - 2026-03-06

### 🐛 Bug Fixes

- *(deps)* Update golang.org/x/net to v0.51.0
- *(deps)* Update opentelemetry-go monorepo (#110)
- *(deps)* Update opentelemetry-go monorepo (#115)

### ⚙️ Miscellaneous Tasks

- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.0 (#111)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.1 (#113)

<!-- generated by git-cliff -->

---

**Note:** Please use **Squash Merge** when merging this PR.

Reviewed-on: #116
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-03-06 19:59:22 +00:00
renovate af15b97d05 fix(deps): update opentelemetry-go monorepo (#115)
Release / release (push) Successful in 1m4s
otelsetup / vulnerabilities (push) Successful in 1m45s
otelsetup / test (push) Successful in 2m32s
pre-commit / pre-commit (push) Successful in 6m32s
2026-03-06 19:41:00 +00:00
renovate 0bc2b48f20 chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.1 (#113)
Release / release (push) Successful in 1m13s
otelsetup / vulnerabilities (push) Successful in 1m40s
otelsetup / test (push) Successful in 2m51s
pre-commit / pre-commit (push) Successful in 6m10s
2026-03-06 15:41:43 +00:00
renovate 65a41418c6 chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.0 (#111)
Release / release (push) Successful in 3m13s
otelsetup / test (push) Successful in 3m20s
otelsetup / vulnerabilities (push) Successful in 4m20s
pre-commit / pre-commit (push) Successful in 9m20s
2026-03-06 14:16:24 +00:00
renovate 235083bb95 fix(deps): update opentelemetry-go monorepo (#110)
Release / release (push) Failing after 1m11s
otelsetup / vulnerabilities (push) Successful in 2m1s
otelsetup / test (push) Successful in 2m43s
pre-commit / pre-commit (push) Successful in 6m7s
2026-03-02 20:18:25 +00:00
argoyle 4ce727b275 Merge pull request 'fix(deps): update golang.org/x/net to v0.51.0' (#108) from fix-vulncheck-xnet into main
Release / release (push) Successful in 1m3s
otelsetup / vulnerabilities (push) Successful in 1m50s
otelsetup / test (push) Successful in 3m6s
pre-commit / pre-commit (push) Successful in 9m39s
Reviewed-on: #108
2026-02-28 23:20:56 +00:00
argoyle 54e7739ea5 fix(deps): update golang.org/x/net to v0.51.0
otelsetup / vulnerabilities (pull_request) Successful in 2m23s
otelsetup / test (pull_request) Successful in 4m47s
pre-commit / pre-commit (pull_request) Successful in 9m11s
Fixes GO-2026-4559: HTTP/2 server panic vulnerability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:57:54 +01:00
8 changed files with 344 additions and 93 deletions
+11 -15
View File
@@ -18,11 +18,10 @@ jobs:
run: go test -race -coverprofile=coverage.txt ./...
- name: Check coverage
uses: vladopajic/go-test-coverage@v2
with:
config: ./.testcoverage.yml
# Download baseline coverage from main branch (for PRs)
id: coverage
run: |
go install github.com/vladopajic/go-test-coverage/v2@latest
go-test-coverage --config ./.testcoverage.yml --github-action-output
- name: Download baseline coverage
if: gitea.event_name == 'pull_request'
uses: actions/download-artifact@v3
@@ -30,14 +29,12 @@ jobs:
name: coverage-baseline
path: ./baseline
continue-on-error: true
# Compare coverage against baseline (for PRs)
- name: Compare coverage
if: gitea.event_name == 'pull_request'
run: |
CURRENT=$(go tool cover -func=coverage.txt | grep "^total:" | awk '{print $NF}' | tr -d '%')
CURRENT="${{ steps.coverage.outputs.total-coverage }}"
if [ -f ./baseline/coverage.txt ]; then
BASE=$(go tool cover -func=./baseline/coverage.txt | grep "^total:" | awk '{print $NF}' | tr -d '%')
BASE=$(cat ./baseline/coverage.txt)
echo "Base coverage: ${BASE}%"
echo "Current coverage: ${CURRENT}%"
if [ "$(echo "$CURRENT < $BASE" | bc -l)" -eq 1 ]; then
@@ -49,8 +46,9 @@ jobs:
echo "No baseline coverage found, skipping comparison"
echo "Current coverage: ${CURRENT}%"
fi
# Upload coverage as baseline (only on main)
- name: Save coverage baseline
if: gitea.ref == 'refs/heads/main'
run: echo "${{ steps.coverage.outputs.total-coverage }}" > coverage.txt
- name: Upload coverage baseline
if: gitea.ref == 'refs/heads/main'
uses: actions/upload-artifact@v3
@@ -58,19 +56,17 @@ jobs:
name: coverage-baseline
path: coverage.txt
retention-days: 90
# Post coverage to PR comment
- name: Post coverage comment
if: gitea.event_name == 'pull_request'
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_URL: ${{ gitea.server_url }}
run: |
COVERAGE=$(go tool cover -func=coverage.txt | grep "^total:" | awk '{print $NF}')
COVERAGE="${{ steps.coverage.outputs.total-coverage }}"
curl -X POST "${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/issues/${{ gitea.event.pull_request.number }}/comments" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"body\": \"## Coverage Report\n\nTotal coverage: **${COVERAGE}**\"}"
-d "{\"body\": \"## Coverage Report\n\nTotal coverage: **${COVERAGE}%**\"}"
vulnerabilities:
runs-on: ubuntu-latest
+3 -3
View File
@@ -11,7 +11,7 @@ repos:
- --allow-multiple-documents
- id: check-added-large-files
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.24.0
rev: v9.25.0
hooks:
- id: commitlint
stages: [ commit-msg ]
@@ -30,10 +30,10 @@ repos:
- id: go-test
- id: gofumpt
- repo: https://github.com/golangci/golangci-lint
rev: v2.10.1
rev: v2.12.2
hooks:
- id: golangci-lint-full
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.0
rev: v8.30.1
hooks:
- id: gitleaks
+1 -1
View File
@@ -1,3 +1,3 @@
{
"version": "v0.2.3"
"version": "v0.3.0"
}
+54
View File
@@ -2,6 +2,60 @@
All notable changes to this project will be documented in this file.
## [0.3.0] - 2026-05-26
### 🚀 Features
- Add eventsourced MetricsRecorder adapter for OpenTelemetry (#142)
## [0.2.7] - 2026-05-09
### 🐛 Bug Fixes
- *(deps)* Update opentelemetry-go monorepo (#131)
- *(ci)* Use go-test-coverage binary directly to fix Gitea Actions (#134)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.90 (#133)
### ⚙️ Miscellaneous Tasks
- *(deps)* Update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.25.0 (#136)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.12.0 (#137)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.12.1 (#138)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.12.2 (#140)
## [0.2.6] - 2026-04-02
### 🐛 Bug Fixes
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.88 (#121)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.89 (#129)
### ⚙️ Miscellaneous Tasks
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.2 (#119)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.3 (#123)
- *(deps)* Update pre-commit hook gitleaks/gitleaks to v8.30.1 (#125)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.4 (#127)
## [0.2.5] - 2026-03-06
### 🐛 Bug Fixes
- *(deps)* Update opentelemetry-go monorepo to v1.42.0 (#117)
## [0.2.4] - 2026-03-06
### 🐛 Bug Fixes
- *(deps)* Update golang.org/x/net to v0.51.0
- *(deps)* Update opentelemetry-go monorepo (#110)
- *(deps)* Update opentelemetry-go monorepo (#115)
### ⚙️ Miscellaneous Tasks
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.0 (#111)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.1 (#113)
## [0.2.3] - 2026-02-19
### 🐛 Bug Fixes
+25 -24
View File
@@ -1,18 +1,20 @@
module gitea.unbound.se/shiny/otelsetup
go 1.25
go 1.25.0
require (
github.com/99designs/gqlgen v0.17.87
go.opentelemetry.io/otel v1.40.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0
go.opentelemetry.io/otel/log v0.16.0
go.opentelemetry.io/otel/sdk v1.40.0
go.opentelemetry.io/otel/sdk/log v0.16.0
go.opentelemetry.io/otel/sdk/metric v1.40.0
go.opentelemetry.io/otel/trace v1.40.0
github.com/99designs/gqlgen v0.17.90
gitlab.com/unboundsoftware/eventsourced/eventsourced v1.23.0
go.opentelemetry.io/otel v1.43.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0
go.opentelemetry.io/otel/log v0.19.0
go.opentelemetry.io/otel/metric v1.43.0
go.opentelemetry.io/otel/sdk v1.43.0
go.opentelemetry.io/otel/sdk/log v0.19.0
go.opentelemetry.io/otel/sdk/metric v1.43.0
go.opentelemetry.io/otel/trace v1.43.0
)
require (
@@ -21,19 +23,18 @@ require (
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/sosodev/duration v1.3.1 // indirect
github.com/vektah/gqlparser/v2 v2.5.32 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
github.com/sosodev/duration v1.4.0 // indirect
github.com/vektah/gqlparser/v2 v2.5.33 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect
go.opentelemetry.io/otel/metric v1.40.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
golang.org/x/net v0.50.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/grpc v1.78.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.35.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
google.golang.org/grpc v1.80.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)
+52 -50
View File
@@ -1,5 +1,5 @@
github.com/99designs/gqlgen v0.17.87 h1:pSnCIMhBQezAE8bc1GNmfdLXFmnWtWl1GRDFEE/nHP8=
github.com/99designs/gqlgen v0.17.87/go.mod h1:fK05f1RqSNfQpd4CfW5qk/810Tqi4/56Wf6Nem0khAg=
github.com/99designs/gqlgen v0.17.90 h1:wSv6blm/PoplU6QoNw83EcQpNtC0HX3/+44vITJOzpk=
github.com/99designs/gqlgen v0.17.90/go.mod h1:GqYrEwYsqCG8VaOsq2kJUCUKwAE1T+u2i+Nj7NtXiVI=
github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
@@ -21,64 +21,66 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE=
github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc=
github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
github.com/vektah/gqlparser/v2 v2.5.33 h1:lRp8aIeNUNbimf/axZd7ETg24q06hBtPaas+TcvI/7E=
github.com/vektah/gqlparser/v2 v2.5.33/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
gitlab.com/unboundsoftware/eventsourced/eventsourced v1.23.0 h1:qcteJH9D7kHaOgLQ0fzlW9dv42hSa0Vluqt7p4kooWA=
gitlab.com/unboundsoftware/eventsourced/eventsourced v1.23.0/go.mod h1:LrA7I7etRmhIC1PjO8c26BHm+gWsy2rC3eSMe5+XUWE=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 h1:9y5sHvAxWzft1WQ4BwqcvA+IFVUJ1Ya75mSAUnFEVwE=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0/go.mod h1:eQqT90eR3X5Dbs1g9YSM30RavwLF725Ris5/XSXWvqE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0 h1:ivlbaajBWJqhcCPniDqDJmRwj4lc6sRT+dCAVKNmxlQ=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0/go.mod h1:u/G56dEKDDwXNCVLsbSrllB2o8pbtFLUC4HpR66r2dc=
go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4=
go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes=
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI=
go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y=
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 h1:GJkybS+crDMdExT/BUNCEgfrmfboztcS6PhvSo88HKM=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0/go.mod h1:NuAyxRYIG2lKX3YQkB+83StTxM7s52PUUkRRiC0wnYI=
go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4=
go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk=
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko=
go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg=
go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk=
go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk=
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M=
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+123
View File
@@ -0,0 +1,123 @@
package otelsetup
import (
"context"
"errors"
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
)
// eventsourcedMeterName is the instrumentation scope for the event-sourcing
// metrics emitted by the adapter returned from NewEventsourcedMetrics.
const eventsourcedMeterName = "gitea.unbound.se/shiny/otelsetup/eventsourced"
// durationBucketsSeconds are explicit histogram boundaries tuned for
// sub-second event-store and command latencies. The SDK default boundaries are
// scaled for milliseconds, which would bucket nearly every second-valued
// observation into the first bucket and make percentiles useless.
var durationBucketsSeconds = []float64{0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10}
// eventsourcedMetrics implements eventsourced.MetricsRecorder by translating
// the framework's Metric values into OpenTelemetry instruments registered on
// the global MeterProvider configured by SetupOTelSDK.
//
// The OTel metric instruments are safe for concurrent use, and the struct is
// immutable after construction, so Record may be called from multiple
// goroutines as the framework requires.
//
// Operation counts are read off each duration histogram's generated _count
// series rather than separate counters; the only standalone counters carry
// information a histogram count cannot (events.loaded sums the number of events
// per load, idempotency.checks counts lookups that have no duration).
type eventsourcedMetrics struct {
commandDuration metric.Float64Histogram
eventStoreDur metric.Float64Histogram
eventsLoaded metric.Int64Counter
eventLoadDur metric.Float64Histogram
snapshotStoreDur metric.Float64Histogram
snapshotLoadDur metric.Float64Histogram
idempotencyCheck metric.Int64Counter
}
// NewEventsourcedMetrics builds an eventsourced.MetricsRecorder that records to
// the global OpenTelemetry MeterProvider. Pass the result to both
// pg.WithMetrics (for event-store operations) and eventsourced.WithMetrics
// (for command handling) so a single recorder covers store and handler
// metrics.
//
// SetupOTelSDK must have run first so the global MeterProvider is configured;
// when metrics are disabled the global provider is a no-op and recording is
// effectively free.
func NewEventsourcedMetrics() (eventsourced.MetricsRecorder, error) {
m := otel.Meter(eventsourcedMeterName)
var errs []error
hist := func(name, desc string) metric.Float64Histogram {
h, err := m.Float64Histogram(
name,
metric.WithDescription(desc),
metric.WithUnit("s"),
metric.WithExplicitBucketBoundaries(durationBucketsSeconds...),
)
errs = append(errs, err)
return h
}
counter := func(name, desc string) metric.Int64Counter {
c, err := m.Int64Counter(name, metric.WithDescription(desc))
errs = append(errs, err)
return c
}
r := &eventsourcedMetrics{
commandDuration: hist("eventsourced.command.duration", "Wall-clock time to process a command in Handle."),
eventStoreDur: hist("eventsourced.event.store.duration", "Time taken to persist a single event."),
eventsLoaded: counter("eventsourced.events.loaded", "Number of events loaded when rehydrating aggregates."),
eventLoadDur: hist("eventsourced.event.load.duration", "Time taken to load events for an aggregate."),
snapshotStoreDur: hist("eventsourced.snapshot.store.duration", "Time taken to persist a snapshot."),
snapshotLoadDur: hist("eventsourced.snapshot.load.duration", "Time taken to load a snapshot."),
idempotencyCheck: counter("eventsourced.idempotency.checks", "Number of command idempotency lookups."),
}
if err := errors.Join(errs...); err != nil {
return nil, err
}
return r, nil
}
// Record implements eventsourced.MetricsRecorder. Metric types the adapter does
// not recognise (for example pg outbox metrics when the outbox is not enabled)
// are ignored.
func (e *eventsourcedMetrics) Record(ctx context.Context, raw eventsourced.Metric) {
switch m := raw.(type) {
case eventsourced.CommandDuration:
e.commandDuration.Record(ctx, m.Duration.Seconds(), metric.WithAttributes(
attribute.String("command.type", m.CommandType),
attribute.Bool("success", m.Success),
))
case eventsourced.EventStored:
e.eventStoreDur.Record(ctx, m.Duration.Seconds(), metric.WithAttributes(
attribute.String("aggregate.type", m.AggregateType),
attribute.String("event.type", m.EventType),
))
case eventsourced.EventsLoaded:
attrs := metric.WithAttributes(attribute.String("aggregate.type", m.AggregateType))
e.eventsLoaded.Add(ctx, int64(m.EventCount), attrs)
e.eventLoadDur.Record(ctx, m.Duration.Seconds(), attrs)
case eventsourced.SnapshotStored:
e.snapshotStoreDur.Record(ctx, m.Duration.Seconds(), metric.WithAttributes(
attribute.String("aggregate.type", m.AggregateType),
attribute.Bool("success", m.Success),
))
case eventsourced.SnapshotLoaded:
e.snapshotLoadDur.Record(ctx, m.Duration.Seconds(), metric.WithAttributes(
attribute.String("aggregate.type", m.AggregateType),
attribute.Bool("found", m.Found),
))
case eventsourced.IdempotencyCheck:
e.idempotencyCheck.Add(ctx, 1, metric.WithAttributes(
attribute.String("aggregate.type", m.AggregateType),
attribute.Bool("hit", m.Hit),
))
}
}
+75
View File
@@ -0,0 +1,75 @@
package otelsetup
import (
"context"
"sort"
"testing"
"time"
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
"go.opentelemetry.io/otel"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)
func TestNewEventsourcedMetrics_RecordsContract(t *testing.T) {
reader := sdkmetric.NewManualReader()
otel.SetMeterProvider(sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)))
r, err := NewEventsourcedMetrics()
if err != nil {
t.Fatalf("NewEventsourcedMetrics returned error: %v", err)
}
if r == nil {
t.Fatal("NewEventsourcedMetrics returned nil recorder")
}
// Recording every known metric type (and an unknown one) must not panic
// and must emit the expected instruments.
for _, m := range []eventsourced.Metric{
eventsourced.CommandDuration{CommandType: "AddEntry", Duration: time.Millisecond, Success: true},
eventsourced.EventStored{AggregateType: "Entry", EventType: "EntryAdded", Duration: time.Millisecond},
eventsourced.EventsLoaded{AggregateType: "Entry", EventCount: 3, Duration: time.Millisecond},
eventsourced.SnapshotStored{AggregateType: "Entry", Duration: time.Millisecond, Success: true},
eventsourced.SnapshotLoaded{AggregateType: "Entry", Found: false, Duration: time.Millisecond},
eventsourced.IdempotencyCheck{AggregateType: "Entry", Hit: true},
unknownMetric{},
} {
r.Record(context.Background(), m)
}
var rm metricdata.ResourceMetrics
if err := reader.Collect(context.Background(), &rm); err != nil {
t.Fatalf("collect: %v", err)
}
got := map[string]bool{}
for _, sm := range rm.ScopeMetrics {
for _, md := range sm.Metrics {
got[md.Name] = true
}
}
want := []string{
"eventsourced.command.duration",
"eventsourced.event.store.duration",
"eventsourced.events.loaded",
"eventsourced.event.load.duration",
"eventsourced.snapshot.store.duration",
"eventsourced.snapshot.load.duration",
"eventsourced.idempotency.checks",
}
var missing []string
for _, w := range want {
if !got[w] {
missing = append(missing, w)
}
}
if len(missing) > 0 {
sort.Strings(missing)
t.Errorf("missing expected metrics: %v", missing)
}
}
type unknownMetric struct{}
func (unknownMetric) IsMetric() {}