21 Commits
Author SHA1 Message Date
releaser 5b128fb3e2 chore(release): prepare for v0.4.2 (#173)
Unbound Release / Check Preconditions (push) Successful in 27s
Unbound Release / Create Tag (push) Skipped
Release / release (push) Successful in 3m24s
Unbound Release / Generate Changelog and Handle PR (push) Successful in 31s
otelsetup / test (push) Skipped
otelsetup / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
Unbound Release / Create Release (push) Successful in 30s
## [0.4.2] - 2026-08-28

### 🐛 Bug Fixes

- *(deps)* Update opentelemetry-go monorepo (#172)

### ⚙️ Miscellaneous Tasks

- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.13.0 (#168)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.13.1 (#170)

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

---

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

Reviewed-on: #173
Co-authored-by: Unbound Releaser <releaser@unbound.se>
2026-08-29 11:25:15 +00:00
renovate 9b04b1b897 fix(deps): update opentelemetry-go monorepo (#172)
otelsetup / vulnerabilities (push) Successful in 59s
pre-commit / pre-commit (push) Successful in 3m16s
Unbound Release / Check Preconditions (push) Successful in 33s
Unbound Release / Create Tag (push) Skipped
otelsetup / test (push) Successful in 1m9s
Unbound Release / Generate Changelog and Handle PR (push) Successful in 43s
Unbound Release / Create Release (push) Successful in 42s
Release / release (push) Successful in 1m32s
2026-08-28 17:14:50 +00:00
renovate d0b6302893 chore(deps): update pre-commit hook golangci/golangci-lint to v2.13.1 (#170)
Unbound Release / Check Preconditions (push) Successful in 26s
Unbound Release / Create Tag (push) Skipped
otelsetup / test (push) Skipped
otelsetup / vulnerabilities (push) Skipped
Unbound Release / Create Release (push) Successful in 28s
Unbound Release / Generate Changelog and Handle PR (push) Successful in 54s
Release / release (push) Successful in 1m25s
pre-commit / pre-commit (push) Successful in 3m12s
2026-08-23 15:15:48 +00:00
renovate fdb17a58c8 chore(deps): update pre-commit hook golangci/golangci-lint to v2.13.0 (#168)
Unbound Release / Check Preconditions (push) Successful in 21s
Unbound Release / Create Tag (push) Skipped
otelsetup / test (push) Skipped
otelsetup / vulnerabilities (push) Skipped
Unbound Release / Generate Changelog and Handle PR (push) Successful in 46s
Release / release (push) Successful in 1m12s
Unbound Release / Create Release (push) Successful in 24s
pre-commit / pre-commit (push) Successful in 2m31s
2026-08-22 23:13:59 +00:00
releaser ece0c99dc3 chore(release): prepare for v0.4.1 (#167)
Unbound Release / Check Preconditions (push) Successful in 22s
Unbound Release / Generate Changelog and Handle PR (push) Successful in 33s
Release / release (push) Successful in 57s
Unbound Release / Create Tag (push) Skipped
Unbound Release / Create Release (push) Successful in 26s
otelsetup / test (push) Successful in 1m9s
otelsetup / vulnerabilities (push) Successful in 53s
pre-commit / pre-commit (push) Successful in 2m22s
## [0.4.1] - 2026-08-06

### 🐛 Bug Fixes

- *(deps)* Update module github.com/99designs/gqlgen to v0.17.92 (#154)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.93 (#158)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.94 (#160)
- *(deps)* Update opentelemetry-go monorepo (#166)

### ⚙️ Miscellaneous Tasks

- *(deps)* Update actions/checkout action to v7 (#152)
- *(deps)* Update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.26.0 (#156)
- *(deps)* Update actions/setup-go action to v7 (#162)
- *(deps)* Update actions/setup-python action to v7 (#164)

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

---

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

Reviewed-on: #167
Co-authored-by: Unbound Releaser <releaser@unbound.se>
2026-08-07 07:29:08 +00:00
renovate 81231179c8 fix(deps): update opentelemetry-go monorepo (#166)
Unbound Release / Check Preconditions (push) Successful in 21s
Unbound Release / Create Release (push) Successful in 22s
otelsetup / test (push) Successful in 1m23s
Release / release (push) Successful in 1m17s
otelsetup / vulnerabilities (push) Successful in 49s
Unbound Release / Create Tag (push) Skipped
Unbound Release / Generate Changelog and Handle PR (push) Successful in 50s
pre-commit / pre-commit (push) Successful in 2m25s
2026-08-06 20:14:21 +00:00
renovate 48c718a183 chore(deps): update actions/setup-python action to v7 (#164)
Unbound Release / Check Preconditions (push) Successful in 27s
Unbound Release / Create Tag (push) Skipped
pre-commit / pre-commit (push) Skipped
Unbound Release / Generate Changelog and Handle PR (push) Successful in 40s
Release / release (push) Successful in 8m35s
Unbound Release / Create Release (push) Successful in 28s
otelsetup / vulnerabilities (push) Failing after 13m24s
otelsetup / test (push) Successful in 4m18s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [actions/setup-python](https://github.com/actions/setup-python) | action | major | `v6` → `v7` |

---

### Release Notes

<details>
<summary>actions/setup-python (actions/setup-python)</summary>

### [`v7.0.0`](https://github.com/actions/setup-python/releases/tag/v7.0.0)

[Compare Source](https://github.com/actions/setup-python/compare/v7.0.0...v7.0.0)

#### What's Changed

##### Enhancements

- Migrate to ESM and upgrade dependencies by [@&#8203;priyagupta108](https://github.com/priyagupta108) in [#&#8203;1330](https://github.com/actions/setup-python/pull/1330)
- Pin SHA commits and update docs with latest versions by [@&#8203;HarithaVattikuti](https://github.com/HarithaVattikuti) in [#&#8203;1338](https://github.com/actions/setup-python/pull/1338)
- Remove the pip-install input by [@&#8203;gowridurgad](https://github.com/gowridurgad) in [#&#8203;1336](https://github.com/actions/setup-python/pull/1336)

##### Bug Fix

- Fix to Classify stderr warning messages as warnings instead of errors in annotations by [@&#8203;lmvysakh](https://github.com/lmvysakh) in [#&#8203;1335](https://github.com/actions/setup-python/pull/1335)
- Validate and retry manifest fetch to prevent silent failures by [@&#8203;priyagupta108](https://github.com/priyagupta108) in [#&#8203;1332](https://github.com/actions/setup-python/pull/1332)

##### Dependency Upgrade

- Bump certifi from 2020.6.20 to 2024.7.4 in /**tests**/data by [@&#8203;dependabot](https://github.com/dependabot) in [#&#8203;1328](https://github.com/actions/setup-python/pull/1328)
- Remove EOL Python versions and Bumps numpy text fixture by [@&#8203;priya-kinthali](https://github.com/priya-kinthali) in [#&#8203;1333](https://github.com/actions/setup-python/pull/1333)
- Upgrade [@&#8203;actions/cache](https://github.com/actions/cache) to 6.2.0 by [@&#8203;philip-gai](https://github.com/philip-gai) in [#&#8203;1337](https://github.com/actions/setup-python/pull/1337)

#### New Contributors

- [@&#8203;lmvysakh](https://github.com/lmvysakh) made their first contribution in [#&#8203;1335](https://github.com/actions/setup-python/pull/1335)
- [@&#8203;philip-gai](https://github.com/philip-gai) made their first contribution in [#&#8203;1337](https://github.com/actions/setup-python/pull/1337)

**Full Changelog**: <https://github.com/actions/setup-python/compare/v6...v7.0.0>

### [`v7`](https://github.com/actions/setup-python/compare/v6.3.0...v7.0.0)

[Compare Source](https://github.com/actions/setup-python/compare/v6.3.0...v7.0.0)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNTcuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI1Ny4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->Reviewed-on: #164

Co-authored-by: Renovate Bot <renovate@unbound.se>
2026-07-25 11:30:35 +00:00
renovate 08962365dc chore(deps): update actions/setup-go action to v7 (#162)
Release / release (push) Successful in 36s
otelsetup / test (push) Successful in 1m18s
otelsetup / vulnerabilities (push) Successful in 56s
pre-commit / pre-commit (push) Successful in 3m0s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [actions/setup-go](https://github.com/actions/setup-go) | action | major | `v6` → `v7` |

---

### Release Notes

<details>
<summary>actions/setup-go (actions/setup-go)</summary>

### [`v7.0.0`](https://github.com/actions/setup-go/releases/tag/v7.0.0)

[Compare Source](https://github.com/actions/setup-go/compare/v7.0.0...v7.0.0)

##### What's Changed

- Migrate to ESM and upgrade dependencies by [@&#8203;priyagupta108](https://github.com/priyagupta108) in [#&#8203;763](https://github.com/actions/setup-go/pull/763)
- chore(deps): bump [@&#8203;actions/cache](https://github.com/actions/cache) to 6.2.0 by [@&#8203;philip-gai](https://github.com/philip-gai) in [#&#8203;771](https://github.com/actions/setup-go/pull/771)

##### New Contributors

- [@&#8203;philip-gai](https://github.com/philip-gai) made their first contribution in [#&#8203;771](https://github.com/actions/setup-go/pull/771)

**Full Changelog**: <https://github.com/actions/setup-go/compare/v6...v7.0.0>

### [`v7`](https://github.com/actions/setup-go/compare/v6.5.0...v7.0.0)

[Compare Source](https://github.com/actions/setup-go/compare/v6.5.0...v7.0.0)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDMuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0My4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: #162
Co-authored-by: Renovate Bot <renovate@unbound.se>
Co-committed-by: Renovate Bot <renovate@unbound.se>
2026-07-19 18:43:59 +00:00
renovate c41b3ea911 fix(deps): update module github.com/99designs/gqlgen to v0.17.94 (#160)
otelsetup / vulnerabilities (push) Successful in 56s
otelsetup / test (push) Successful in 1m18s
Release / release (push) Successful in 1m6s
pre-commit / pre-commit (push) Successful in 3m12s
2026-07-12 15:24:43 +00:00
renovate c436c8219c fix(deps): update module github.com/99designs/gqlgen to v0.17.93 (#158)
Release / release (push) Successful in 51s
pre-commit / pre-commit (push) Successful in 3m49s
otelsetup / vulnerabilities (push) Failing after 10m46s
otelsetup / test (push) Failing after 11m17s
2026-06-29 00:58:34 +00:00
renovate 4524b6dba8 chore(deps): update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.26.0 (#156)
otelsetup / vulnerabilities (push) Successful in 1m3s
otelsetup / test (push) Successful in 1m40s
Release / release (push) Successful in 45s
pre-commit / pre-commit (push) Successful in 3m38s
2026-06-27 22:35:57 +00:00
renovate 8c9e9e3876 fix(deps): update module github.com/99designs/gqlgen to v0.17.92 (#154)
pre-commit / pre-commit (push) Successful in 3m48s
Release / release (push) Successful in 48s
otelsetup / test (push) Successful in 1m41s
otelsetup / vulnerabilities (push) Successful in 1m10s
2026-06-24 15:12:35 +00:00
renovate 3f0d9eff99 chore(deps): update actions/checkout action to v7 (#152)
Release / release (push) Successful in 1m2s
otelsetup / vulnerabilities (push) Successful in 1m30s
otelsetup / test (push) Successful in 2m23s
pre-commit / pre-commit (push) Successful in 5m46s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [actions/checkout](https://github.com/actions/checkout) | action | major | `v6` → `v7` |

---

### Release Notes

<details>
<summary>actions/checkout (actions/checkout)</summary>

### [`v7.0.0`](https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v700)

[Compare Source](https://github.com/actions/checkout/compare/v7.0.0...v7.0.0)

- Block checking out fork PR for pull\_request\_target and workflow\_run by [@&#8203;aiqiaoy](https://github.com/aiqiaoy) in [#&#8203;2454](https://github.com/actions/checkout/pull/2454)
- Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the minor-actions-dependencies group across 1 directory by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2458](https://github.com/actions/checkout/pull/2458)
- Bump flatted from 3.3.1 to 3.4.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2460](https://github.com/actions/checkout/pull/2460)
- Bump js-yaml from 4.1.0 to 4.2.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2461](https://github.com/actions/checkout/pull/2461)
- Bump [@&#8203;actions/core](https://github.com/actions/core) and [@&#8203;actions/tool-cache](https://github.com/actions/tool-cache) and Remove uuid by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2459](https://github.com/actions/checkout/pull/2459)
- upgrade module to esm and update dependencies by [@&#8203;aiqiaoy](https://github.com/aiqiaoy) in [#&#8203;2463](https://github.com/actions/checkout/pull/2463)
- Bump the minor-npm-dependencies group across 1 directory with 3 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2462](https://github.com/actions/checkout/pull/2462)

### [`v7`](https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v700)

[Compare Source](https://github.com/actions/checkout/compare/v6.0.3...v7.0.0)

- Block checking out fork PR for pull\_request\_target and workflow\_run by [@&#8203;aiqiaoy](https://github.com/aiqiaoy) in [#&#8203;2454](https://github.com/actions/checkout/pull/2454)
- Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the minor-actions-dependencies group across 1 directory by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2458](https://github.com/actions/checkout/pull/2458)
- Bump flatted from 3.3.1 to 3.4.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2460](https://github.com/actions/checkout/pull/2460)
- Bump js-yaml from 4.1.0 to 4.2.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2461](https://github.com/actions/checkout/pull/2461)
- Bump [@&#8203;actions/core](https://github.com/actions/core) and [@&#8203;actions/tool-cache](https://github.com/actions/tool-cache) and Remove uuid by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2459](https://github.com/actions/checkout/pull/2459)
- upgrade module to esm and update dependencies by [@&#8203;aiqiaoy](https://github.com/aiqiaoy) in [#&#8203;2463](https://github.com/actions/checkout/pull/2463)
- Bump the minor-npm-dependencies group across 1 directory with 3 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2462](https://github.com/actions/checkout/pull/2462)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMjAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjIyMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: #152
Co-authored-by: Renovate Bot <renovate@unbound.se>
Co-committed-by: Renovate Bot <renovate@unbound.se>
2026-06-21 15:45:20 +00:00
releaser 4732aa5ab2 chore(release): prepare for v0.4.0 (#151)
Release / release (push) Successful in 57s
otelsetup / vulnerabilities (push) Successful in 1m29s
otelsetup / test (push) Successful in 2m31s
pre-commit / pre-commit (push) Successful in 5m11s
## [0.4.0] - 2026-06-16

### 🚀 Features

- *(metrics)* Add SubscriptionMetrics OTel observer for subscriptions (#150)

### 🐛 Bug Fixes

- *(deps)* Update opentelemetry-go monorepo (#146)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.91 (#148)

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

---

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

Reviewed-on: #151
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-06-16 13:22:52 +00:00
argoyle c00564cdcb feat(metrics): add SubscriptionMetrics OTel observer for subscriptions (#150)
Release / release (push) Successful in 1m31s
otelsetup / vulnerabilities (push) Successful in 2m8s
otelsetup / test (push) Successful in 2m47s
pre-commit / pre-commit (push) Successful in 6m47s
2026-06-16 13:14:14 +00:00
renovate 2836af0242 fix(deps): update module github.com/99designs/gqlgen to v0.17.91 (#148)
otelsetup / test (push) Successful in 2m24s
otelsetup / vulnerabilities (push) Successful in 1m39s
Release / release (push) Successful in 1m0s
pre-commit / pre-commit (push) Successful in 6m2s
2026-06-14 15:33:23 +00:00
renovate 212369811f fix(deps): update opentelemetry-go monorepo (#146)
otelsetup / test (push) Successful in 2m23s
Release / release (push) Failing after 1m3s
otelsetup / vulnerabilities (push) Successful in 1m39s
pre-commit / pre-commit (push) Successful in 6m1s
2026-05-31 12:07:55 +00:00
releaser afac050279 chore(release): prepare for v0.3.1 (#145)
Release / release (push) Successful in 52s
otelsetup / vulnerabilities (push) Successful in 1m51s
otelsetup / test (push) Successful in 2m27s
pre-commit / pre-commit (push) Successful in 6m30s
## [0.3.1] - 2026-05-29

### 🐛 Bug Fixes

- Set service.instance.id for unique instance label (#144)

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

---

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

Reviewed-on: #145
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-05-29 06:47:04 +00:00
argoyle afa847c76c fix: set service.instance.id for unique instance label (#144)
Release / release (push) Successful in 54s
pre-commit / pre-commit (push) Successful in 6m51s
otelsetup / vulnerabilities (push) Failing after 10m48s
otelsetup / test (push) Failing after 10m50s
2026-05-29 06:39:14 +00:00
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
12 changed files with 545 additions and 97 deletions
+4 -4
View File
@@ -10,8 +10,8 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: 'stable'
- name: Run tests
@@ -71,8 +71,8 @@ jobs:
vulnerabilities:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: 'stable'
- name: Check vulnerabilities
+3 -3
View File
@@ -13,11 +13,11 @@ jobs:
env:
SKIP: no-commit-to-branch
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: stable
- uses: actions/setup-python@v6
- uses: actions/setup-python@v7
with:
python-version: '3.14'
- name: Install goimports
+2 -2
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.25.0
rev: v9.26.0
hooks:
- id: commitlint
stages: [ commit-msg ]
@@ -30,7 +30,7 @@ repos:
- id: go-test
- id: gofumpt
- repo: https://github.com/golangci/golangci-lint
rev: v2.12.2
rev: v2.13.1
hooks:
- id: golangci-lint-full
- repo: https://github.com/gitleaks/gitleaks
+1 -1
View File
@@ -1,3 +1,3 @@
{
"version": "v0.2.7"
"version": "v0.4.2"
}
+50
View File
@@ -2,6 +2,56 @@
All notable changes to this project will be documented in this file.
## [0.4.2] - 2026-08-28
### 🐛 Bug Fixes
- *(deps)* Update opentelemetry-go monorepo (#172)
### ⚙️ Miscellaneous Tasks
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.13.0 (#168)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.13.1 (#170)
## [0.4.1] - 2026-08-07
### 🐛 Bug Fixes
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.92 (#154)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.93 (#158)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.94 (#160)
- *(deps)* Update opentelemetry-go monorepo (#166)
### ⚙️ Miscellaneous Tasks
- *(deps)* Update actions/checkout action to v7 (#152)
- *(deps)* Update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.26.0 (#156)
- *(deps)* Update actions/setup-go action to v7 (#162)
- *(deps)* Update actions/setup-python action to v7 (#164)
## [0.4.0] - 2026-06-16
### 🚀 Features
- *(metrics)* Add SubscriptionMetrics OTel observer for subscriptions (#150)
### 🐛 Bug Fixes
- *(deps)* Update opentelemetry-go monorepo (#146)
- *(deps)* Update module github.com/99designs/gqlgen to v0.17.91 (#148)
## [0.3.1] - 2026-05-29
### 🐛 Bug Fixes
- Set service.instance.id for unique instance label (#144)
## [0.3.0] - 2026-05-26
### 🚀 Features
- Add eventsourced MetricsRecorder adapter for OpenTelemetry (#142)
## [0.2.7] - 2026-05-09
### 🐛 Bug Fixes
+25 -24
View File
@@ -3,37 +3,38 @@ module gitea.unbound.se/shiny/otelsetup
go 1.25.0
require (
github.com/99designs/gqlgen v0.17.90
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/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
github.com/99designs/gqlgen v0.17.94
gitlab.com/unboundsoftware/eventsourced/eventsourced v1.23.0
go.opentelemetry.io/otel v1.46.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.22.0
go.opentelemetry.io/otel/log v0.22.0
go.opentelemetry.io/otel/metric v1.46.0
go.opentelemetry.io/otel/sdk v1.46.0
go.opentelemetry.io/otel/sdk/log v0.22.0
go.opentelemetry.io/otel/sdk/metric v1.46.0
go.opentelemetry.io/otel/trace v1.46.0
)
require (
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/logr v1.4.4 // 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.28.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
github.com/sosodev/duration v1.4.0 // indirect
github.com/vektah/gqlparser/v2 v2.5.33 // indirect
github.com/vektah/gqlparser/v2 v2.5.36 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
go.opentelemetry.io/otel/metric 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
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 // indirect
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
golang.org/x/net v0.58.0 // indirect
golang.org/x/sync v0.22.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.41.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 // indirect
google.golang.org/grpc v1.83.1 // indirect
google.golang.org/protobuf v1.36.12 // indirect
)
+58 -62
View File
@@ -1,18 +1,14 @@
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/99designs/gqlgen v0.17.94 h1:+3EUDVgX/8gDyDL+7NUqCo4cy2ylylwW0GvR1dGiEsA=
github.com/99designs/gqlgen v0.17.94/go.mod h1:o+XaAMpPA/AX4rqeiK03tZUb/5T+WCgpRDD4aujgdas=
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=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -21,65 +17,65 @@ 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.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/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY=
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.33 h1:lRp8aIeNUNbimf/axZd7ETg24q06hBtPaas+TcvI/7E=
github.com/vektah/gqlparser/v2 v2.5.33/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/vektah/gqlparser/v2 v2.5.36 h1:CN9mKVHgMkc+XftdOWIhb4HEL8wKSYkFAqhf8booa7s=
github.com/vektah/gqlparser/v2 v2.5.36/go.mod h1:cAJ9qwVgPaUkWv6Gn8vn0mqOE0Ui5Pn56wNy5396XWo=
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.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.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0 h1:AP23h/mFgb/lc7tdck1Kfn9qxsM8TAeNPCU5C3pzaps=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0/go.mod h1:K4EqCe1b4kGk5WR690ntg9LaBfsPoV32FwthbyoptuA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 h1:OFnwLJr+pF3iHrlGSzbxyuo6/6HyBlnlN1CWEJmBVcw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0/go.mod h1:716wFneO0ov19A2beH5hjfh9AK5z/VWNAtDijp1Y0/g=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0 h1:KrC1YrQeSt46ITMWAbgQx1M1eV1/1TKzttrBzymPmss=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0/go.mod h1:zDSEzoEqsOrgBeGvH66KRgxh90VonFyJqBHA0Pk3+rM=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.22.0 h1:kvMAiLEudKmk+CSG+iYbU8vTUGNNDaf/V09OO5lrTwI=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.22.0/go.mod h1:L9Dlksri+MdT1cb2gIiA1cJJYW3Y92ipvDjNxYEyaDI=
go.opentelemetry.io/otel/log v0.22.0 h1:5DBNnfvaJ6CVdkJ+Jle8Tzs50aSSv49TXGj9XRsEYw0=
go.opentelemetry.io/otel/log v0.22.0/go.mod h1:gzOt/R67vF2GniAqWu8Qv0SXy89f71muHcrkz76PCdc=
go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU=
go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4=
go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
go.opentelemetry.io/otel/sdk/log v0.22.0 h1:PRL+s6P63XT4E/bheEflopPUpVxuvANqZwtt89yhoGk=
go.opentelemetry.io/otel/sdk/log v0.22.0/go.mod h1:JNp0sBELrjCTcu5W3GzABVypeU6vDJjBS+X0JISuz+g=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0 h1:infPnfNrhCNgOUZRs3gWUg8vhoBUHihq02gwK05gzlg=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0/go.mod h1:gkQZA3z15Bv3KU9vigBTi8dFechSozRP7v94X4VZv+s=
go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
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.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=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
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.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
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=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 h1:ax2KzoSRIZU/M0cIxri3pKxy99vniH1PVxWC6si/eZI=
google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688/go.mod h1:1RJ9BQGyNdZwkGc1eTqkErfRZ6RJyYPHZo73BZ1vQqI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 h1:cYNAzI2sUwhmCcoj9TxvihSrqsxt6uIkj3rDRhSDmW4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA=
google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y=
google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+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() {}
+11 -1
View File
@@ -22,7 +22,17 @@ import (
// SetupOTelSDK bootstraps the OpenTelemetry pipeline.
func SetupOTelSDK(ctx context.Context, enabled bool, serviceName, buildVersion, environment string) (func(context.Context) error, error) {
if os.Getenv("OTEL_RESOURCE_ATTRIBUTES") == "" {
if err := os.Setenv("OTEL_RESOURCE_ATTRIBUTES", fmt.Sprintf("service.name=%s,service.version=%s,service.environment=%s", serviceName, buildVersion, environment)); err != nil {
// service.instance.id makes every pod a distinct telemetry resource. The
// OTLP→Prometheus exporter maps it to the `instance` label on metrics and
// target_info, which keeps multi-replica services from colliding on a
// single series and gives joins a unique (job, instance) key. Hostname is
// the pod name under Kubernetes; fall back to the service name if it is
// unavailable so the attribute is always present.
instanceID, err := os.Hostname()
if err != nil || instanceID == "" {
instanceID = serviceName
}
if err := os.Setenv("OTEL_RESOURCE_ATTRIBUTES", fmt.Sprintf("service.name=%s,service.version=%s,service.environment=%s,service.instance.id=%s", serviceName, buildVersion, environment, instanceID)); err != nil {
return func(context.Context) error {
return nil
}, err
+85
View File
@@ -0,0 +1,85 @@
package otelsetup
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
)
// subscriptionMeterName is the instrumentation scope for the cross-service
// subscription push metrics emitted by SubscriptionMetrics.
const subscriptionMeterName = "gitea.unbound.se/shiny/otelsetup/subscriptions"
// SubscriptionMetrics records cross-service subscription push outcomes (the
// read-your-writes subscriptions described in ADR-0012) as OpenTelemetry
// counters.
//
// Its method set (Pushed/PushSkipped/Dropped/ChannelFull) satisfies the
// Observer interface of gitea.unbound.se/shiny/subscriptions *structurally* —
// otelsetup does not import that library. A service constructs it and passes it
// to the registry:
//
// metrics, err := otelsetup.NewSubscriptionMetrics("availableCompanies")
// if err != nil { return err }
// reg := subscriptions.New[T](subscriptions.WithObserver(metrics))
//
// The WithObserver call type-checks the structural match, so a drift in the
// Observer interface fails the service build. Add a
// `var _ subscriptions.Observer = (*otelsetup.SubscriptionMetrics)(nil)` next to
// it for an explicit guard.
//
// Outcomes are recorded against a low-cardinality (subscription, outcome) pair.
// The subscriber key (company id / user email) the Observer methods receive is
// deliberately NOT used as a metric attribute — that would be unbounded
// cardinality; the key stays in the subscriptions library's logs for
// correlation.
type SubscriptionMetrics struct {
notifications metric.Int64Counter
subscription attribute.KeyValue
}
// NewSubscriptionMetrics builds a SubscriptionMetrics that records to the global
// OpenTelemetry MeterProvider. subscription is the low-cardinality name of the
// subscription field (e.g. "availableCompanies", "entryBasesChanged"), recorded
// as an attribute so one counter covers every subscription.
//
// 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 NewSubscriptionMetrics(subscription string) (*SubscriptionMetrics, error) {
c, err := otel.Meter(subscriptionMeterName).Int64Counter(
"subscription.notifications",
metric.WithDescription("Cross-service subscription push outcomes, by outcome (pushed/skipped/dropped/channel_full)."),
)
if err != nil {
return nil, err
}
return &SubscriptionMetrics{
notifications: c,
subscription: attribute.String("subscription", subscription),
}, nil
}
func (s *SubscriptionMetrics) record(outcome string) {
s.notifications.Add(context.Background(), 1, metric.WithAttributes(
s.subscription,
attribute.String("outcome", outcome),
))
}
// Pushed records a change that was gated and delivered to the key's subscribers
// — the denominator for a skip/drop rate.
func (s *SubscriptionMetrics) Pushed(string) { s.record("pushed") }
// PushSkipped records a push skipped because the read view never reflected the
// change within the retry budget.
func (s *SubscriptionMetrics) PushSkipped(string) { s.record("skipped") }
// Dropped records a notification dropped because the worker queue was full.
func (s *SubscriptionMetrics) Dropped(string) { s.record("dropped") }
// ChannelFull records a notification dropped because a subscriber's buffer was
// full.
func (s *SubscriptionMetrics) ChannelFull(string) { s.record("channel_full") }
+108
View File
@@ -0,0 +1,108 @@
package otelsetup
import (
"context"
"testing"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric/noop"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)
// observerShape mirrors gitea.unbound.se/shiny/subscriptions.Observer. This
// compile-time assertion guards that SubscriptionMetrics still satisfies that
// interface structurally, without otelsetup importing the library.
//
// KEEP IN SYNC with subscriptions.Observer: this only proves SubscriptionMetrics
// matches this local copy. The authoritative check that the local copy still
// matches the real interface is the `subscriptions.WithObserver(...)` call site
// in each consuming service — keep a `var _ subscriptions.Observer` guard there.
type observerShape interface {
Pushed(string)
PushSkipped(string)
Dropped(string)
ChannelFull(string)
}
var _ observerShape = (*SubscriptionMetrics)(nil)
// TestSubscriptionMetrics_DisabledProviderIsSafe proves the "recording is free
// when metrics are disabled" claim: with the default global no-op provider, the
// methods neither panic nor emit instruments.
func TestSubscriptionMetrics_DisabledProviderIsSafe(t *testing.T) {
otel.SetMeterProvider(noop.NewMeterProvider())
m, err := NewSubscriptionMetrics("entryBasesChanged")
if err != nil {
t.Fatalf("NewSubscriptionMetrics returned error: %v", err)
}
// Must not panic on the no-op provider.
m.Pushed("c1")
m.PushSkipped("c1")
m.Dropped("c1")
m.ChannelFull("c1")
}
func TestNewSubscriptionMetrics_RecordsOutcomes(t *testing.T) {
reader := sdkmetric.NewManualReader()
otel.SetMeterProvider(sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)))
m, err := NewSubscriptionMetrics("availableCompanies")
if err != nil {
t.Fatalf("NewSubscriptionMetrics returned error: %v", err)
}
// The subscriber key is ignored for metrics; different keys must not create
// new series (cardinality guard is implicit — we only label by outcome).
m.Pushed("c1")
m.Pushed("c2")
m.PushSkipped("c1")
m.Dropped("c1")
m.ChannelFull("c1")
var rm metricdata.ResourceMetrics
if err := reader.Collect(context.Background(), &rm); err != nil {
t.Fatalf("collect: %v", err)
}
counts := map[string]int64{}
dataPoints := 0
found := false
for _, sm := range rm.ScopeMetrics {
for _, md := range sm.Metrics {
if md.Name != "subscription.notifications" {
continue
}
found = true
sum, ok := md.Data.(metricdata.Sum[int64])
if !ok {
t.Fatalf("expected Sum[int64], got %T", md.Data)
}
for _, dp := range sum.DataPoints {
dataPoints++
sub, _ := dp.Attributes.Value(attribute.Key("subscription"))
if sub.AsString() != "availableCompanies" {
t.Errorf("unexpected subscription attribute: %q", sub.AsString())
}
outcome, _ := dp.Attributes.Value(attribute.Key("outcome"))
counts[outcome.AsString()] += dp.Value
}
}
}
if !found {
t.Fatal("subscription.notifications counter not emitted")
}
// One series per outcome, keyed by outcome only (not by subscriber key).
if dataPoints != 4 {
t.Errorf("expected 4 data points (one per outcome), got %d", dataPoints)
}
want := map[string]int64{"pushed": 2, "skipped": 1, "dropped": 1, "channel_full": 1}
for k, v := range want {
if counts[k] != v {
t.Errorf("outcome %q: got %d, want %d", k, counts[k], v)
}
}
}