Compare commits

..

158 Commits

Author SHA1 Message Date
Julien Neuhart
fb472124c4 feat(chromium): skip or waits for networkIdle2 event 2026-03-11 21:17:09 +01:00
Julien Neuhart
f584fa2dc0 feat(otel): add better metrics for chromium and libreoffice 2026-03-11 20:55:42 +01:00
Julien Neuhart
81d43cfbad fix(Dockerfile): use uid/gid instead of gotenberg in chown 2026-03-11 18:45:50 +01:00
Julien Neuhart
fe72902cdb feat(Dockerfile): reducing size even more 2026-03-11 18:26:43 +01:00
Julien Neuhart
8898bd2b4a refactor(Dockerfile): better Java modules 2026-03-08 16:16:14 +01:00
Julien Neuhart
a62abef215 refactor(Dockerfile): remove fonts 2026-03-08 16:08:33 +01:00
Julien Neuhart
cf9fd7eedc refactor(pdfengines): embeds => attachments 2026-03-08 15:49:09 +01:00
Julien Neuhart
7af3cd1ff5 test(integration): add bookmarks routes 2026-03-04 21:34:16 +01:00
Julien Neuhart
4296474889 feat(pdfengines): add read bookmarks pdfcpu implementation 2026-03-04 20:52:56 +01:00
Julien Neuhart
bfde451e4e feat(pdfengines): add bookmarks read route 2026-03-04 20:48:33 +01:00
Julien Neuhart
fd8c5441d8 feat(pdfengines): add bookmarks write pdfcpu implementation 2026-03-04 20:30:31 +01:00
Julien Neuhart
d7421748d0 feat(pdfengines): add bookmarks write route and update the merge route with this feature 2026-03-04 20:25:06 +01:00
Julien Neuhart
0e13cc3ed8 docs(README): typo in sponsors [skip ci] 2026-02-24 21:36:53 +01:00
dependabot[bot]
cb49e8e4d1 chore(deps): bump github.com/labstack/echo/v4 from 4.15.0 to 4.15.1 (#1476)
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.15.0 to 4.15.1.
- [Release notes](https://github.com/labstack/echo/releases)
- [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/labstack/echo/compare/v4.15.0...v4.15.1)

---
updated-dependencies:
- dependency-name: github.com/labstack/echo/v4
  dependency-version: 4.15.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 07:31:26 +01:00
Julien Neuhart
3113e034f6 fix(tests): update unconverter and add concurrency in debug output 2026-02-22 11:47:30 +01:00
Julien Neuhart
85291fdec3 fix(Dockerfile): bump go version to 1.26 2026-02-21 21:30:33 +01:00
Julien Neuhart
57e1b7efda chore(golangci-lint): bump golangci-lint to v2.10.1 2026-02-21 17:54:46 +01:00
Julien Neuhart
be78a71bb7 feat(Makefile): add go fix to fmt command 2026-02-20 21:22:34 +01:00
Julien Neuhart
2baa59cb3a refactor(gofix): modernize 2026-02-20 21:21:19 +01:00
Julien Neuhart
aea7c5952a chore(go): bump Go to 1.26.0 2026-02-20 21:19:26 +01:00
Julien Neuhart
cbde321d3b docs(README): still small improvements 2026-02-20 20:44:04 +01:00
Julien Neuhart
aa5de988cf docs(README): small improvements 2026-02-20 20:13:35 +01:00
dependabot[bot]
fd485a0d3e chore(deps): bump golang.org/x/net from 0.49.0 to 0.50.0 (#1471)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.49.0 to 0.50.0.
- [Commits](https://github.com/golang/net/compare/v0.49.0...v0.50.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.50.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-19 11:06:42 +01:00
dependabot[bot]
aea06a98b7 chore(deps): bump golang.org/x/text from 0.33.0 to 0.34.0 (#1470)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.33.0 to 0.34.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-19 11:05:10 +01:00
Daniel Moran
82401bdfdd feat(chromium): add support for emulated media features in Chromium (#1474)
Closes https://github.com/gotenberg/gotenberg/issues/1460

It can be easier to print a "clean" PDF of some pages if you emulate
media features like `prefers-reduced-motion`. Add support for that
emulation.
2026-02-17 20:16:28 +01:00
Tom Brouws
12c25a2d21 feat(chromium): re-add concurrency support for Chromium (#1467)
* feat: add concurrency support to ProcessSupervisor

- Replace the single-slot mutex channel with a configurable semaphore to
allow multiple concurrent tasks.
- Add drain logic to ensure all active
tasks complete before process restarts.

* feat: add chromium-max-concurrency flag

- Add a --chromium-max-concurrency flag (1-6) to the Chromium module to
control how many conversions run in parallel.
- Update LibreOffice to pass maxConcurrency=1 as LibreOffice only supports
a single concurrent conversion.

* test: add integration tests for concurrent Chromium conversions

- Add concurrent request support to the integration test framework with
new step definitions for sending parallel requests and asserting on all
responses.
- Add a feature file for concurrent HTML to PDF conversions.
2026-02-13 10:00:58 +01:00
dependabot[bot]
241d5077c9 chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.12 to 4.26.1 (#1464)
Bumps [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) from 4.25.12 to 4.26.1.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.12...v4.26.1)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.26.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-13 09:59:40 +01:00
David
37757315d0 feat(Dockerfile): manage system time zone (#1465)
* displays timezone in debug information

* fixes cs

* fixes debug_test.go
2026-02-13 09:59:23 +01:00
John W. Mendes
1195c37508 chore(go): bump Go to 1.25.7 2026-02-10 09:14:20 +01:00
Julien Neuhart
3d9b2deb59 fix(style): AGENTS.md 2026-02-08 19:22:36 +01:00
Julien Neuhart
32d948554f docs(ai): add AGENTS.md 2026-02-08 17:32:43 +01:00
Julien Neuhart
b7a6b7aba2 Revert "chore(.gitignore): add junie folder"
This reverts commit 05e15a1d06.
2026-02-08 17:31:58 +01:00
Julien Neuhart
05e15a1d06 chore(.gitignore): add junie folder 2026-02-08 12:52:14 +01:00
Julien Neuhart
f57ecb6ef2 fix(exiftool): remove derived tags to prevent side effects when writing metadata (fixes #1463) 2026-01-29 17:25:09 +01:00
Julien Neuhart
45318497d2 chore(deps): update Go dependencies 2026-01-27 11:20:29 +00:00
dependabot[bot]
b762143d75 chore(deps): bump golang.org/x/net from 0.48.0 to 0.49.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.48.0 to 0.49.0.
- [Commits](https://github.com/golang/net/compare/v0.48.0...v0.49.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.49.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-26 09:23:09 +01:00
dependabot[bot]
ba1a730d3a chore(deps-dev): bump prettier from 3.7.4 to 3.8.1
Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.1)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-26 09:23:01 +01:00
Adam Romanek
463bb2f91c fix(webhook): detach context from request lifecycle to prevent cancellation in async mode 2026-01-26 09:11:48 +01:00
Adam Romanek
e14cab0c8b fix(api): propagate request context to stop processing on client disconnect 2026-01-26 09:11:48 +01:00
Daniel Moran
3220ca4140 feat(chromium): add waitForSelector option to Chromium conversions (#1446)
* Add `waitForSelector` option to Chromium conversions

Closes #960

As an alternative to waiting on an expression, this allows users to wait
for a specific node matching a selector to become visible in the HTML /
at the remote URL before converting to PDF.

* Fix style / prettify
2026-01-17 14:57:10 +01:00
David
92de0cf6fe feat(prometheus): add new flag --prometheus-metrics-path 2026-01-14 10:04:57 +01:00
dependabot[bot]
d111591c8b chore(deps): bump golang.org/x/term from 0.38.0 to 0.39.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.38.0 to 0.39.0.
- [Commits](https://github.com/golang/term/compare/v0.38.0...v0.39.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-version: 0.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-12 09:22:10 +01:00
dependabot[bot]
935686b9e3 chore(deps): bump golang.org/x/text from 0.32.0 to 0.33.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.32.0 to 0.33.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-12 09:18:20 +01:00
John W. Mendes
b1ad21c7d3 chore(go): update Go version to 1.25.5 (#1440)
* Update Go to 1.25.5

* Update go version in go.mod
2026-01-05 15:42:47 +01:00
dependabot[bot]
4f800c8a76 chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.11 to 4.25.12 (#1438)
Bumps [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) from 4.25.11 to 4.25.12.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.11...v4.25.12)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 13:19:58 +01:00
dependabot[bot]
5c498219ed chore(deps): bump github.com/labstack/echo/v4 from 4.14.0 to 4.15.0 (#1439)
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.14.0 to 4.15.0.
- [Release notes](https://github.com/labstack/echo/releases)
- [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/labstack/echo/compare/v4.14.0...v4.15.0)

---
updated-dependencies:
- dependency-name: github.com/labstack/echo/v4
  dependency-version: 4.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 13:19:43 +01:00
markfrost
0b211c39eb feat(chromium): add IgnoreResourceHttpStatusDomains option to filter out resources based on their hostnames (#1434)
* Introduced `IgnoreResourceHttpStatusDomains` option to filter out resources based on their hostnames

- Introduced `IgnoreResourceHttpStatusDomains` option to filter out resources based on their hostnames during HTTP status code checks.
- Updated relevant functions to handle domain normalization and matching.
- Enhanced the form data handling to include the new option.
- Added integration test scenario to verify the functionality of ignoring specified domains.

* Updated the `normalizeDomains` function to initialize the `normalized` slice with a predefined capacity based on the input `domains` slice length, improving memory allocation efficiency.
2025-12-25 15:36:45 +01:00
dependabot[bot]
77b9776d9c chore(deps): bump github.com/labstack/echo/v4 from 4.13.4 to 4.14.0
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.13.4 to 4.14.0.
- [Release notes](https://github.com/labstack/echo/releases)
- [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/labstack/echo/compare/v4.13.4...v4.14.0)

---
updated-dependencies:
- dependency-name: github.com/labstack/echo/v4
  dependency-version: 4.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-17 09:28:49 +01:00
dependabot[bot]
04e596b616 chore(deps): bump golang.org/x/text from 0.31.0 to 0.32.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.31.0 to 0.32.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.31.0...v0.32.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-17 09:25:25 +01:00
dependabot[bot]
9fba76fe5c chore(deps-dev): bump prettier from 3.7.3 to 3.7.4
Bumps [prettier](https://github.com/prettier/prettier) from 3.7.3 to 3.7.4.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.3...3.7.4)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.7.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-11 10:12:14 +01:00
Julien Neuhart
8b9858aa66 fix(chromium): resource intensive health check 2025-12-03 22:34:39 +01:00
dependabot[bot]
2f7218b09c chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.10 to 4.25.11
Bumps [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) from 4.25.10 to 4.25.11.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.10...v4.25.11)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 10:11:22 +01:00
dependabot[bot]
0a05091241 chore(deps-dev): bump prettier from 3.6.2 to 3.7.3
Bumps [prettier](https://github.com/prettier/prettier) from 3.6.2 to 3.7.3.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.6.2...3.7.3)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.7.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 10:11:09 +01:00
dependabot[bot]
507d0cb2e2 chore(deps): bump go.uber.org/zap from 1.27.0 to 1.27.1
Bumps [go.uber.org/zap](https://github.com/uber-go/zap) from 1.27.0 to 1.27.1.
- [Release notes](https://github.com/uber-go/zap/releases)
- [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/zap/compare/v1.27.0...v1.27.1)

---
updated-dependencies:
- dependency-name: go.uber.org/zap
  dependency-version: 1.27.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 09:02:55 +01:00
dependabot[bot]
fb61948244 chore(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 09:02:11 +01:00
Alex Weston
15fdc99ec0 fix(chromium): add net::ERR_HTTP2_PROTOCOL_ERROR in the EventLoadingFailed list 2025-11-21 21:30:03 +01:00
dependabot[bot]
dd07c73c28 chore(deps): bump golang.org/x/crypto from 0.44.0 to 0.45.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.44.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.44.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-20 08:52:48 +01:00
Julien Neuhart
43354cafb1 chore(deps): update Go dependencies 2025-11-15 15:15:50 +01:00
Julien Neuhart
b2c3187690 fix(chromium): better native errors handling 2025-11-15 15:10:09 +01:00
Julien Neuhart
4a788ce9d8 fix(lint): non-used method in tests 2025-11-13 22:12:02 +01:00
Julien Neuhart
f9ad8bd2d5 test(integration): add more tags, complete embed feature tests suite, fix order with metadata 2025-11-13 22:08:28 +01:00
Julien Neuhart
4429aea8a4 chore(tests): rename embed feature file 2025-11-13 20:33:10 +01:00
Julien Neuhart
7a60e82d03 chore(deps): use node 24.11 for dev tools 2025-11-10 13:14:50 +00:00
dependabot[bot]
3544e9c355 chore(deps): bump golangci/golangci-lint-action from 8 to 9
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 8 to 9.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v8...v9)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-10 13:32:15 +01:00
dependabot[bot]
ca4f0141c6 chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.5.1+incompatible to 28.5.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.5.1...v28.5.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.5.2+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-10 09:20:23 +01:00
dependabot[bot]
fcaa26a84d chore(deps): bump golang.org/x/sync from 0.17.0 to 0.18.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.17.0 to 0.18.0.
- [Commits](https://github.com/golang/sync/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-10 08:57:38 +01:00
dependabot[bot]
ea103d3070 chore(deps): bump github.com/testcontainers/testcontainers-go
Bumps [github.com/testcontainers/testcontainers-go](https://github.com/testcontainers/testcontainers-go) from 0.39.0 to 0.40.0.
- [Release notes](https://github.com/testcontainers/testcontainers-go/releases)
- [Commits](https://github.com/testcontainers/testcontainers-go/compare/v0.39.0...v0.40.0)

---
updated-dependencies:
- dependency-name: github.com/testcontainers/testcontainers-go
  dependency-version: 0.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-10 08:57:25 +01:00
Tom Quist
286efbe548 chore(deps): bump Go from 1.25.0 to 1.25.4 2025-11-06 16:42:20 +01:00
Hubert Lenoir
a0ee800002 feat(pdfengines): add embed feature 2025-11-05 13:57:23 +01:00
hubert.lenoir
f4d3fba306 feat: add tests tags 2025-11-04 17:44:37 +01:00
dependabot[bot]
d5a58cfcb5 chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.9 to 4.25.10
Bumps [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) from 4.25.9 to 4.25.10.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.9...v4.25.10)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-03 06:36:00 +01:00
Julien Neuhart
0e6bb27ecf fix(chromium): add missing wrapped error 2025-10-24 14:49:54 +00:00
Julien Neuhart
83fdc01df1 fix(chromium): accept case-insensitive values for the cookies' sameSite attribute - closes #1331 2025-10-24 14:46:14 +00:00
Julien Neuhart
c7ccabc6cb fix(chromium): mark the flag --chromium-incognito as deprecated and ignore its value 2025-10-24 14:03:17 +00:00
pebosi
3eefe33e64 Update pdfcpu version 2025-10-22 09:26:02 +02:00
dependabot[bot]
c44dc7f0ab chore(deps): bump github.com/mholt/archives from 0.1.4 to 0.1.5
Bumps [github.com/mholt/archives](https://github.com/mholt/archives) from 0.1.4 to 0.1.5.
- [Release notes](https://github.com/mholt/archives/releases)
- [Commits](https://github.com/mholt/archives/compare/v0.1.4...v0.1.5)

---
updated-dependencies:
- dependency-name: github.com/mholt/archives
  dependency-version: 0.1.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 14:02:16 +02:00
dependabot[bot]
1639d82348 chore(deps): bump actions/setup-node from 5 to 6
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 14:02:06 +02:00
dependabot[bot]
b31e520731 chore(deps-dev): bump prettier-plugin-gherkin from 3.1.2 to 3.1.3
Bumps [prettier-plugin-gherkin](https://github.com/mapado/prettier-plugin-gherkin) from 3.1.2 to 3.1.3.
- [Release notes](https://github.com/mapado/prettier-plugin-gherkin/releases)
- [Changelog](https://github.com/mapado/prettier-plugin-gherkin/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mapado/prettier-plugin-gherkin/compare/v3.1.2...v3.1.3)

---
updated-dependencies:
- dependency-name: prettier-plugin-gherkin
  dependency-version: 3.1.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 14:01:50 +02:00
dependabot[bot]
e85d4143c0 chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.5.0+incompatible to 28.5.1+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.5.0...v28.5.1)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.5.1+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 10:03:53 +02:00
dependabot[bot]
da20f04e25 chore(deps): bump github.com/chromedp/chromedp from 0.14.1 to 0.14.2
Bumps [github.com/chromedp/chromedp](https://github.com/chromedp/chromedp) from 0.14.1 to 0.14.2.
- [Release notes](https://github.com/chromedp/chromedp/releases)
- [Commits](https://github.com/chromedp/chromedp/compare/v0.14.1...v0.14.2)

---
updated-dependencies:
- dependency-name: github.com/chromedp/chromedp
  dependency-version: 0.14.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 10:03:44 +02:00
dependabot[bot]
9a49ea426e chore(deps): bump golang.org/x/net from 0.44.0 to 0.46.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.44.0 to 0.46.0.
- [Commits](https://github.com/golang/net/compare/v0.44.0...v0.46.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.46.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 10:03:23 +02:00
dependabot[bot]
c0c4c21682 chore(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 10:03:15 +02:00
Hugo Tacla
c7424dfcb3 feat(Dockerfile): add basic LibreOffice Hyphenation support 2025-10-09 12:45:52 +02:00
Hugo Tacla
e33ca6af12 fix(deps): revert indirect nwaples/rardecode/v2 bump 2025-10-09 07:44:43 +02:00
Julien Neuhart
9dc6e308b6 ci(deps): update golangci-lint to v2.5.0 2025-10-07 09:52:59 +00:00
Julien Neuhart
4fe2ff5553 chore(deps): update No Emoji to v2.051 2025-10-07 09:44:38 +00:00
Julien Neuhart
e5ccb82db8 chore(deps): update Go dependencies 2025-10-07 09:43:41 +00:00
Julien Neuhart
63ae987010 feat(build): add ppc64le architecture (#1344)
* Support ppc64le architecture

# Conflicts:
#	.github/workflows/continuous-delivery.yml
#	.github/workflows/continuous-integration.yml

* Adding descriptive missing tags

* empty commit for triggering CI

* ci(ppc64le): wrong runner

* fix(ci): iincrease timeout for integration tests to 40 minutes

---------

Co-authored-by: Andrea Esposito <andrea.esposito@horsa.it>
2025-10-07 09:46:24 +02:00
dependabot[bot]
efa0d3fd75 chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.4.0+incompatible to 28.5.0+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.4.0...v28.5.0)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.5.0+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 07:42:18 +02:00
dependabot[bot]
fd5930bc56 chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.8 to 4.25.9
Bumps [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) from 4.25.8 to 4.25.9.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.8...v4.25.9)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 07:41:53 +02:00
Julien Neuhart
a057c6253b chore(deps): update Go dependencies 2025-09-26 13:15:44 +00:00
Julien Neuhart
ed5d1fa891 fix(Dockerfile): remove upx stage 2025-09-20 00:57:17 +02:00
Julien Neuhart
76d36d18be chore(deps): update Go dependencies 2025-09-17 07:02:45 +00:00
dependabot[bot]
a78c433a60 chore(deps): bump golang.org/x/net from 0.43.0 to 0.44.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.43.0 to 0.44.0.
- [Commits](https://github.com/golang/net/compare/v0.43.0...v0.44.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.44.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-16 13:53:51 +02:00
Julien Neuhart
aff7530cb0 feat(build): use trixie-backports for LibreOffice 25.8 - closes #1323 2025-09-09 19:58:14 +02:00
Julien Neuhart
e7e7267fc2 docs(README): add JetBrains logo 2025-09-09 19:37:27 +02:00
dependabot[bot]
9aaab2de3b chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.3.3+incompatible to 28.4.0+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.3.3...v28.4.0)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.4.0+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 09:21:34 +02:00
dependabot[bot]
8f0121a92d chore(deps): bump golang.org/x/sync from 0.16.0 to 0.17.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.16.0 to 0.17.0.
- [Commits](https://github.com/golang/sync/compare/v0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 09:21:19 +02:00
dependabot[bot]
beb1e386c2 chore(deps): bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.23.0 to 1.23.2.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.23.0...v1.23.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 09:21:01 +02:00
dependabot[bot]
5b84a5e0e9 chore(deps): bump actions/setup-node from 4 to 5
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 5.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 09:20:44 +02:00
dependabot[bot]
a9613651a5 chore(deps): bump actions/setup-go from 5 to 6
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 09:20:22 +02:00
Julien Neuhart
d6ebc7f230 chore(pdfengines): better custom error message if invalid args 2025-09-04 14:49:04 +02:00
Julien Neuhart
84ca118524 chore(deps): update Go dependencies 2025-09-04 14:49:04 +02:00
Julien Neuhart
0ad6623e24 fix(pdgengines): encrypt behavior accross different engines 2025-09-04 14:49:04 +02:00
Julien Neuhart
ba944f9dc2 chore: slight improvement of the encrypt feature to be more in line with others features 2025-09-04 14:49:04 +02:00
Stevenson Michel
99307befdd feat: add PDF encryption feature (#1217)
* Adding PDF encryption option

* LibreOffice
* QPDF
* PDFtk
* pdfcpu

* Update pkg/modules/pdfengines/pdfengines.go

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>

* npx prettier

* go fmt

* PR comments

* Update test/integration/scenario/scenario.go

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>

* renamed ProtectWithPassword to encrypt

* more clean up

* Use the same input path as requested

* This commit completes the encryption implementation

* Clean up. Added webhook, disable route and download from tests

---------

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>
2025-09-04 14:49:04 +02:00
Julien Neuhart
638c4e6b23 chore(deps): update Go dependencies 2025-09-01 17:29:00 +02:00
Julien Neuhart
18bb7ef00d ci(actions): switch to actions/checkout@v5 2025-08-31 18:19:21 +02:00
Julien Neuhart
3dd9ce1fcd feat(chromium): add MathJaX support 2025-08-29 21:06:20 +02:00
Julien Neuhart
fd4814194c chore(deps): update Go dependencies 2025-08-29 20:20:48 +02:00
Julien Neuhart
4d526fe419 fix(build): use buffered invoke mode and do not auto-start LibreOffice and Chromium 2025-08-29 20:20:18 +02:00
Julien Neuhart
50d1b187bb fix(build): switch from /home/gotenberg to /opt/gotenberg for hype´ data 2025-08-20 09:38:05 +00:00
Julien Neuhart
f54f78d186 chore(build): use Chromium for all arch 2025-08-18 21:08:14 +02:00
Julien Neuhart
97ec4949d7 chore(deps): bump debian from 12-slim to 13-slim 2025-08-18 20:55:19 +02:00
dependabot[bot]
f08b9d389b chore(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 06:58:48 +02:00
Julien Neuhart
4fc94cae24 chore(deps): npm update 2025-08-15 17:23:09 +02:00
Julien Neuhart
8cab8230e6 chore(deps): update noto-color-emoji to v2.048 2025-08-15 17:22:18 +02:00
Julien Neuhart
b7afa49c9f chore(deps): update pdfcpu to v0.11.0 2025-08-15 17:21:10 +02:00
Julien Neuhart
e0b5ccb41d chore(go): update to 1.25 2025-08-15 17:15:01 +02:00
Julien Neuhart
fb63ffb919 ci(lint): update golangci-lint 2025-08-15 17:14:44 +02:00
Julien Neuhart
cb98b0c937 feat(misc): add --gotenberg-hide-banner flag 2025-08-15 07:36:47 +02:00
Julien Neuhart
bee56cfd99 fix(ci): add missing outputs for AWS Lambda tags 2025-08-15 07:24:12 +02:00
Julien Neuhart
9e130614ce fix(ci): ignore empty tags in push step - second attempt 2025-08-14 22:03:53 +02:00
Julien Neuhart
2f487d2e83 fix(ci): ignore empty tags in push step 2025-08-14 21:37:41 +02:00
Julien Neuhart
1ff4b3a4fc fix(ci): add missing AWS Lambda tags to push step 2025-08-14 21:12:46 +02:00
Julien Neuhart
e86d38c52c feat(build): add default configuration for Cloud Run variant 2025-08-14 20:46:43 +02:00
Julien Neuhart
d371ae8ceb chore(build): add missing GOTENBERG_BUILD_DEBUG_DATA configuration for AWS Lambda 2025-08-14 20:46:09 +02:00
Julien Neuhart
a9d10b2bf3 fix(build): missing args for AWS Lambda Dockerfile 2025-08-14 20:44:03 +02:00
Julien Neuhart
d6ffd193d3 ci(build): #540 add AWS Lambda support 2025-08-14 20:40:38 +02:00
Julien Neuhart
2635213947 feat(build): #540 add AWS Lambda support 2025-08-14 20:39:53 +02:00
Julien Neuhart
d496cbfb53 fix(sort): better sorting algorithm - fixes #1287 2025-08-12 21:21:03 +02:00
Julien Neuhart
db8f0ad9ee fix(chromium): hypen-data now work everytime 2025-08-12 20:54:53 +02:00
dependabot[bot]
8d795a4317 chore(deps): bump golang.org/x/net from 0.42.0 to 0.43.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.42.0 to 0.43.0.
- [Commits](https://github.com/golang/net/compare/v0.42.0...v0.43.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 09:46:29 +02:00
dependabot[bot]
1a9ae456dd chore(deps): bump github.com/chromedp/chromedp from 0.14.0 to 0.14.1
Bumps [github.com/chromedp/chromedp](https://github.com/chromedp/chromedp) from 0.14.0 to 0.14.1.
- [Release notes](https://github.com/chromedp/chromedp/releases)
- [Commits](https://github.com/chromedp/chromedp/compare/v0.14.0...v0.14.1)

---
updated-dependencies:
- dependency-name: github.com/chromedp/chromedp
  dependency-version: 0.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 09:46:18 +02:00
dependabot[bot]
4e9d7a3f8c chore(deps): bump github.com/docker/go-connections from 0.5.0 to 0.6.0
Bumps [github.com/docker/go-connections](https://github.com/docker/go-connections) from 0.5.0 to 0.6.0.
- [Commits](https://github.com/docker/go-connections/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: github.com/docker/go-connections
  dependency-version: 0.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 09:02:09 +02:00
dependabot[bot]
087967befb chore(deps): bump golang.org/x/term from 0.33.0 to 0.34.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.33.0 to 0.34.0.
- [Commits](https://github.com/golang/term/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-version: 0.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 08:59:00 +02:00
Julien Neuhart
02ad6c7834 feat(webhook): switch to --webhook-enable-sync-mode flag instead of header 2025-08-09 16:17:27 +02:00
Yash Narwal
fc11f557fa feat(webhook) add support for sync upload with webhook url (#1233)
* Add support for having sync upload with webhook url

* Update tests

* Make SendOutputFileParams interface private

* Make interface params private
2025-08-08 09:25:46 +02:00
RJ Sampson
f299f3ed20 fix(chromium): Enable GPU support
Chromium 139 is set to deprecate the Swiftshader backend entirely:

https://chromestatus.com/feature/5166674414927872

And 138 doesn't provide fallback without explicitly enabling it,
breaking functionality such as WebGL in Gotenberg

Re-enable GPU support to work around this

Signed-off-by: RJ Sampson <rj.sampson@chainguard.dev>
2025-08-06 10:31:00 +02:00
Julien Neuhart
94c831cd05 fix(integration): failing scenarios 2025-08-03 18:49:14 +02:00
Julien Neuhart
53b4c70e4b chore: prettify 2025-08-03 18:19:43 +02:00
Julien Neuhart
6ff5109b00 fix(integration): non-working scenarios because of a remote service down 2025-08-03 18:02:35 +02:00
dependabot[bot]
339afe614c chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.3.2+incompatible to 28.3.3+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.3.2...v28.3.3)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.3+incompatible
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-30 09:51:05 +02:00
dependabot[bot]
911fdd3067 chore(deps): bump github.com/testcontainers/testcontainers-go
---
updated-dependencies:
- dependency-name: github.com/testcontainers/testcontainers-go
  dependency-version: 0.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 09:02:03 +02:00
dependabot[bot]
588e27e6d1 chore(deps): bump github.com/cucumber/godog from 0.15.0 to 0.15.1
Bumps [github.com/cucumber/godog](https://github.com/cucumber/godog) from 0.15.0 to 0.15.1.
- [Release notes](https://github.com/cucumber/godog/releases)
- [Changelog](https://github.com/cucumber/godog/blob/main/CHANGELOG.md)
- [Commits](https://github.com/cucumber/godog/compare/v0.15.0...v0.15.1)

---
updated-dependencies:
- dependency-name: github.com/cucumber/godog
  dependency-version: 0.15.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 09:01:53 +02:00
Andrea
3a71032d62 tests(integration): use same targeted platform for integration-tools image (#1275)
* Use same targeted platform integration-tools image @ integration tests

* run make fmt
2025-07-16 11:30:41 +02:00
dependabot[bot]
59a091e7dc chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.3.1+incompatible to 28.3.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.3.1...v28.3.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.2+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-15 11:19:21 +02:00
dependabot[bot]
0e250a99ed chore(deps): bump golang.org/x/net from 0.41.0 to 0.42.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.41.0 to 0.42.0.
- [Commits](https://github.com/golang/net/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-15 11:13:41 +02:00
dependabot[bot]
f73b72753f chore(deps): bump github.com/docker/docker
---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.1+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 08:57:27 +02:00
dependabot[bot]
00a85b0d90 chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.5 to 4.25.6
---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 08:57:17 +02:00
dependabot[bot]
e79d7e6fb5 chore(deps-dev): bump prettier-plugin-sh from 0.17.4 to 0.18.0
Bumps [prettier-plugin-sh](https://github.com/un-ts/prettier) from 0.17.4 to 0.18.0.
- [Release notes](https://github.com/un-ts/prettier/releases)
- [Changelog](https://github.com/un-ts/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un-ts/prettier/compare/prettier-plugin-sh@0.17.4...prettier-plugin-sh@0.18.0)

---
updated-dependencies:
- dependency-name: prettier-plugin-sh
  dependency-version: 0.18.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:46:30 +02:00
dependabot[bot]
ef745dc378 chore(deps-dev): bump prettier from 3.6.0 to 3.6.2
Bumps [prettier](https://github.com/prettier/prettier) from 3.6.0 to 3.6.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.6.0...3.6.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.6.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:46:03 +02:00
dependabot[bot]
ac5dfb7ff0 chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.2.2+incompatible to 28.3.0+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.2.2...v28.3.0)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.0+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:45:45 +02:00
dependabot[bot]
51b0841171 chore(deps): bump github.com/mholt/archives from 0.1.2 to 0.1.3
Bumps [github.com/mholt/archives](https://github.com/mholt/archives) from 0.1.2 to 0.1.3.
- [Release notes](https://github.com/mholt/archives/releases)
- [Commits](https://github.com/mholt/archives/compare/v0.1.2...v0.1.3)

---
updated-dependencies:
- dependency-name: github.com/mholt/archives
  dependency-version: 0.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:45:34 +02:00
dependabot[bot]
57264da21b chore(deps): bump github.com/alexliesenfeld/health from 0.8.0 to 0.8.1
Bumps [github.com/alexliesenfeld/health](https://github.com/alexliesenfeld/health) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/alexliesenfeld/health/releases)
- [Changelog](https://github.com/alexliesenfeld/health/blob/main/CHANGELOG.md)
- [Commits](https://github.com/alexliesenfeld/health/compare/v0.8.0...v0.8.1)

---
updated-dependencies:
- dependency-name: github.com/alexliesenfeld/health
  dependency-version: 0.8.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:51 +02:00
dependabot[bot]
16f740b318 chore(deps): bump github.com/hashicorp/go-retryablehttp
Bumps [github.com/hashicorp/go-retryablehttp](https://github.com/hashicorp/go-retryablehttp) from 0.7.7 to 0.7.8.
- [Changelog](https://github.com/hashicorp/go-retryablehttp/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/go-retryablehttp/compare/v0.7.7...v0.7.8)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-retryablehttp
  dependency-version: 0.7.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:38 +02:00
dependabot[bot]
2ba70141cc chore(deps): bump github.com/chromedp/chromedp from 0.13.6 to 0.13.7
Bumps [github.com/chromedp/chromedp](https://github.com/chromedp/chromedp) from 0.13.6 to 0.13.7.
- [Release notes](https://github.com/chromedp/chromedp/releases)
- [Commits](https://github.com/chromedp/chromedp/compare/v0.13.6...v0.13.7)

---
updated-dependencies:
- dependency-name: github.com/chromedp/chromedp
  dependency-version: 0.13.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:27 +02:00
dependabot[bot]
e945329d91 chore(deps-dev): bump prettier from 3.5.3 to 3.6.0
Bumps [prettier](https://github.com/prettier/prettier) from 3.5.3 to 3.6.0.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.5.3...3.6.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:13 +02:00
184 changed files with 9070 additions and 2947 deletions

1
.env
View File

@@ -3,4 +3,5 @@ DOCKER_REGISTRY=gotenberg
DOCKER_REPOSITORY=gotenberg
DOCKERFILE=build/Dockerfile
DOCKERFILE_CLOUDRUN=build/Dockerfile.cloudrun
DOCKERFILE_AWS_LAMBDA=build/Dockerfile.aws-lambda
DOCKER_BUILD_CONTEXT='.'

View File

@@ -14,7 +14,7 @@ inputs:
description: The Docker Hub password
required: true
platform:
description: linux/amd64, linux/386, linux/arm64, linux/arm/v7
description: linux/amd64, linux/ppc64le, linux/386, linux/arm64, linux/arm/v7
required: true
version:
description: Gotenberg version
@@ -34,6 +34,9 @@ outputs:
tags_cloud_run:
description: Comma separated list of Cloud Run tags (linux/amd64 only)
value: ${{ steps.build.outputs.tags_cloud_run }}
tags_aws_lambda:
description: Comma separated list of AWS Lambda tags (linux/amd64 and linux/arm64 only)
value: ${{ steps.build.outputs.tags_aws_lambda }}
runs:
using: composite
@@ -45,7 +48,7 @@ runs:
uses: docker/setup-buildx-action@v3
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Log in to Docker Hub
if: inputs.docker_hub_username != ''
@@ -79,7 +82,7 @@ runs:
shell: bash
run: |
.github/actions/build-test-push/push.sh \
--tags "${{ steps.build.outputs.tags }},${{ steps.build.outputs.tags_cloud_run }}" \
--tags "${{ steps.build.outputs.tags }},${{ steps.build.outputs.tags_cloud_run }},${{ steps.build.outputs.tags_aws_lambda }}" \
--dry-run "${{ inputs.dry_run }}"
- name: Outputs
@@ -87,3 +90,4 @@ runs:
run: |
echo "tags=${{ steps.build.outputs.tags }}"
echo "tags_cloud_run=${{ steps.build.outputs.tags_cloud_run }}"
echo "tags_aws_lambda=${{ steps.build.outputs.tags_aws_lambda }}"

View File

@@ -56,6 +56,7 @@ fi
# Build tags arrays.
tags=()
tags_cloud_run=()
tags_aws_lambda=()
IFS='/' read -ra arch <<< "$platform"
IFS='.' read -ra semver <<< "$version"
@@ -79,6 +80,13 @@ if [ "${#semver[@]}" -eq 3 ]; then
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor-cloudrun")
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor.$patch-cloudrun")
fi
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:latest-aws-lambda-${arch[1]}")
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major-aws-lambda-${arch[1]}")
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor-aws-lambda-${arch[1]}")
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor.$patch-aws-lambda-${arch[1]}")
fi
else
echo
echo "Non-semver version detected, fallback to $version"
@@ -87,10 +95,15 @@ else
if [ "$platform" = "linux/amd64" ]; then
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version-cloudrun")
fi
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version-aws-lambda-${arch[1]}")
fi
fi
tags_flags=()
tags_cloud_run_flags=()
tags_aws_lambda_flags=()
echo "Will use the following tags:"
for tag in "${tags[@]}"; do
@@ -101,6 +114,10 @@ for tag in "${tags_cloud_run[@]}"; do
tags_cloud_run_flags+=("-t" "$tag")
echo "- $tag"
done
for tag in "${tags_aws_lambda[@]}"; do
tags_aws_lambda_flags+=("-t" "$tag")
echo "- $tag"
done
echo
# Build images.
@@ -138,24 +155,30 @@ cmd="docker buildx build \
"
run_cmd "$cmd"
if [ "$platform" != "linux/amd64" ]; then
echo "⚠️ Skip Cloud Run variant(s)"
echo "✅ Done!"
echo "tags=$(join "," "${tags[@]}")" >> "$GITHUB_OUTPUT"
echo "tags_cloud_run=$(join "," "${tags_cloud_run[@]}")" >> "$GITHUB_OUTPUT"
exit 0
if [ "$platform" = "linux/amd64" ]; then
cmd="docker build \
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
--build-arg GOTENBERG_VERSION=$version \
${tags_cloud_run_flags[*]} \
-f $DOCKERFILE_CLOUDRUN $DOCKER_BUILD_CONTEXT
"
run_cmd "$cmd"
fi
cmd="docker build \
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
--build-arg GOTENBERG_VERSION=$version \
${tags_cloud_run_flags[*]} \
-f $DOCKERFILE_CLOUDRUN $DOCKER_BUILD_CONTEXT
"
run_cmd "$cmd"
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
cmd="docker build \
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
--build-arg GOTENBERG_VERSION=$version \
${tags_aws_lambda_flags[*]} \
-f $DOCKERFILE_AWS_LAMBDA $DOCKER_BUILD_CONTEXT
"
run_cmd "$cmd"
fi
echo "✅ Done!"
echo "tags=$(join "," "${tags[@]}")" >> "$GITHUB_OUTPUT"
echo "tags_cloud_run=$(join "," "${tags_cloud_run[@]}")" >> "$GITHUB_OUTPUT"
echo "tags_aws_lambda=$(join "," "${tags_aws_lambda[@]}")" >> "$GITHUB_OUTPUT"
exit 0

View File

@@ -32,7 +32,13 @@ echo "Push tag(s) 📦"
echo
echo "Tag(s) to push:"
IFS=',' read -ra tags_to_push <<< "$tags"
IFS=',' read -ra tmp_tags_to_push <<< "$tags"
tags_to_push=()
for tag in "${tmp_tags_to_push[@]}"; do
[ -n "$tag" ] && tags_to_push+=("$tag")
done
for tag in "${tags_to_push[@]}"; do
echo "- $tag"
done

View File

@@ -40,6 +40,7 @@ IFS=',' read -ra tags_to_delete <<< "$tags"
if [ -n "$snapshot_version" ]; then
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version")
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version-cloudrun")
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version-aws-lambda")
fi
echo "Will delete the following tag(s):"

View File

@@ -31,7 +31,7 @@ runs:
uses: docker/setup-buildx-action@v3
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Log in to Docker Hub
uses: docker/login-action@v3

View File

@@ -56,6 +56,7 @@ declare -A merge_map
for tag in "${tags_to_merge[@]}"; do
target_tag="${tag//-amd64/}"
target_tag="${target_tag//-ppc64le/}"
target_tag="${target_tag//-arm64/}"
target_tag="${target_tag//-arm/}"
target_tag="${target_tag//-386/}"

View File

@@ -14,9 +14,10 @@ jobs:
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build and push
id: build_push
@@ -34,9 +35,10 @@ jobs:
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build and push
id: build_push
@@ -48,15 +50,37 @@ jobs:
platform: linux/386
skip_integrations_tests: true
release_ppc64le:
name: Release linux/ppc64le
runs-on: ubuntu-24.04-ppc64le
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Build and push
id: build_push
uses: ./.github/actions/build-test-push
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
version: ${{ github.event.release.tag_name }}
platform: linux/ppc64le
skip_integrations_tests: true
release_arm64:
name: Release linux/arm64
runs-on: ubuntu-24.04-arm
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build and push
id: build_push
@@ -74,9 +98,10 @@ jobs:
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build and push
id: build_push
@@ -92,20 +117,29 @@ jobs:
needs:
- release_amd64
- release_386
- release_ppc64le
- release_arm64
- release_arm_v7
name: Merge and clean release tags
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Merge
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }}"
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_ppc64le.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }}"
alternate_registry: thecodingmachine
- name: Merge AWS Lambda
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.release_amd64.outputs.tags_aws_lambda }},${{ needs.release_arm64.outputs.tags_aws_lambda }}"
alternate_registry: thecodingmachine
- name: Clean
@@ -113,4 +147,4 @@ jobs:
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }}"
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_ppc64le.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }},${{ needs.release_amd64.outputs.tags_aws_lambda }},${{ needs.release_arm64.outputs.tags_aws_lambda }}"

View File

@@ -21,27 +21,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Run linters
uses: golangci/golangci-lint-action@v8
uses: golangci/golangci-lint-action@v9
with:
version: v2.1.6
version: v2.10.1
lint-prettier:
name: Lint non-Golang codebase
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: .node-version
@@ -59,10 +59,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: go.mod
@@ -78,9 +78,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -92,6 +93,30 @@ jobs:
platform: linux/amd64
alternate_repository: snapshot
snapshot_ppc64le:
if: github.event_name == 'pull_request'
needs:
- test-unit
name: Snapshot linux/ppc64le
runs-on: ubuntu-24.04-ppc64le
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
uses: ./.github/actions/build-test-push
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
version: pr-${{ github.event.pull_request.number }}
platform: linux/ppc64le
alternate_repository: snapshot
snapshot_386:
if: github.event_name == 'pull_request'
needs:
@@ -101,9 +126,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -124,9 +150,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -147,9 +174,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -165,6 +193,7 @@ jobs:
needs:
- snapshot_amd64
- snapshot_386
- snapshot_ppc64le
- snapshot_arm64
- snapshot_arm_v7
name: Secrets access check
@@ -187,27 +216,35 @@ jobs:
- merge_clean_snapshot_guard
- snapshot_amd64
- snapshot_386
- snapshot_ppc64le
- snapshot_arm64
- snapshot_arm_v7
name: Merge and clean snapshot tags
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Merge
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }}"
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_ppc64le.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }}"
- name: Merge AWS Lambda
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.snapshot_amd64.outputs.tags_aws_lambda }},${{ needs.snapshot_arm64.outputs.tags_aws_lambda }}"
- name: Clean
uses: ./.github/actions/clean
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }}"
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_ppc64le.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }},${{ needs.snapshot_amd64.outputs.tags_aws_lambda }},${{ needs.snapshot_arm64.outputs.tags_aws_lambda }}"
edge_amd64:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
@@ -218,9 +255,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -240,9 +278,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -253,6 +292,29 @@ jobs:
version: edge
platform: linux/386
edge_ppc64le:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs:
- test-unit
name: Edge linux/ppc64le
runs-on: ubuntu-24.04-ppc64le
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
uses: ./.github/actions/build-test-push
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
version: edge
platform: linux/ppc64le
edge_arm64:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs:
@@ -262,9 +324,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -284,9 +347,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build, test and push
id: build_test_push
@@ -301,20 +365,29 @@ jobs:
needs:
- edge_amd64
- edge_386
- edge_ppc64le
- edge_arm64
- edge_arm_v7
name: Merge and clean edge tags
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Merge
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }}"
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_ppc64le.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }}"
alternate_registry: thecodingmachine
- name: Merge AWS Lambda
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.edge_amd64.outputs.tags_aws_lambda }},${{ needs.edge_arm64.outputs.tags_aws_lambda }}"
alternate_registry: thecodingmachine
- name: Clean
@@ -322,4 +395,4 @@ jobs:
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }}"
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_ppc64le.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }},${{ needs.edge_amd64.outputs.tags_aws_lambda }},${{ needs.edge_arm64.outputs.tags_aws_lambda }}"

View File

@@ -14,7 +14,7 @@ jobs:
continue-on-error: true
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Cleanup
uses: ./.github/actions/clean

View File

@@ -1 +1 @@
23.9.0
24.11.0

66
AGENTS.md Normal file
View File

@@ -0,0 +1,66 @@
# Operational Guidelines for Gotenberg
As an AI agent working on the Gotenberg repository, you are expected to act with the diligence and architectural foresight of a Senior Go Engineer. Gotenberg is a widely used production dependency; stability and backward compatibility are paramount.
## 1. Core Philosophy & Stability
- **Backward Compatibility is Law:** This project creates a public API. Never modify existing flags, configuration environment variables, or API form fields unless explicitly instructed to perform a breaking change. If a change is breaking, it must be flagged immediately in the plan.
- **Defensive Programming:** Assume input data is malformed. Handle errors explicitly. Do not panic.
- **Atomic Commits:** Isolate refactoring from feature additions. A Pull Request should do one thing well.
## 2. Development Workflow & Tooling
You must rely strictly on the project's Makefile for build and verification tasks. Do not run `go` commands directly unless debugging a specific package requires it.
- **Formatting:** Run `make fmt` to format Go code before committing.
- **Linting:**
- Run `make lint` to ensure Go code strictly adheres to the `.golangci.yml` configuration.
- Run `make lint-prettier` to verify formatting for non-Go files (Markdown, YAML, etc.).
- Zero linting errors are permitted.
- **Building:** Run `make build` to verify compilation and Docker image construction.
## 3. Architecture & Code Structure
- **Idiomatic Go:** Follow "Effective Go" principles.
- **Directory Separation:**
- `cmd/`: Application entry points only. Contains wiring and startup logic. **No business logic is permitted here.**
- `pkg/`: Core library code and modules. All business logic resides here.
- **Module System:** Gotenberg is modular (e.g., Chromium, LibreOffice). When adding features, determine if they belong to an existing module or require a new strict isolation.
## 4. Testing Standards
Gotenberg utilizes a split testing strategy. **Integration tests are the primary and preferred method for verifying features.**
- **Integration Tests (`make test-integration`):**
- **First Priority:** Always start here when adding features or routes.
- Gotenberg uses **Gherkin (Godog)** for end-to-end verification.
- You **must** create or update the corresponding `.feature` file in `test/integration`.
- These tests run within the Docker context; ensure environment consistency.
- **Unit Tests (`make test-unit`):**
- Use table-driven tests for pure logic within `pkg/`.
- Mock external dependencies (filesystem, network) where appropriate.
## 5. Documentation Requirements
- **No README Updates:** Do not modify the root `README.md` unless explicitly asked.
- **GoDoc is Mandatory:**
- **New Packages:** If creating a new package, you must include a `doc.go` file containing the package-level documentation.
- **Exported Symbols:** Every exported function, type, constant, and variable must have a proper GoDoc comment starting with its name.
- **Quality:** Comments must be complete sentences explaining _what_ the symbol does and _how_ to use it.
- **Example:**
```go
// Convert transforms the input document to PDF using the Chromium engine.
// It returns an error if the connection to the browser instance fails.
func Convert(...) error
```
## 6. Definition of Done
A task is considered complete only when:
1. The code compiles via `make build`.
2. The code is formatted via `make fmt`.
3. All linters pass via `make lint` and `make lint-prettier`.
4. Integration scenarios pass via `make test-integration`.
5. Unit tests pass via `make test-unit`.
6. All exported symbols and new packages have compliant GoDoc.

161
Makefile
View File

@@ -10,6 +10,8 @@ build: ## Build the Gotenberg's Docker image
-t $(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY):$(GOTENBERG_VERSION) \
-f $(DOCKERFILE) $(DOCKER_BUILD_CONTEXT)
TZ=UTC
GOTENBERG_HIDE_BANNER=false
GOTENBERG_GRACEFUL_SHUTDOWN_DURATION=30s
GOTENBERG_BUILD_DEBUG_DATA=true
API_PORT=3000
@@ -18,22 +20,25 @@ API_BIND_IP=
API_START_TIMEOUT=30s
API_TIMEOUT=30s
API_BODY_LIMIT=
API_ROOT_PATH="/"
API_TRACE_HEADER=Gotenberg-Trace
API_ROOT_PATH=/
API_CORRELATION_ID_HEADER=Gotenberg-Trace
API_ENABLE_BASIC_AUTH=false
GOTENBERG_API_BASIC_AUTH_USERNAME=
GOTENBERG_API_BASIC_AUTH_PASSWORD=
API-DOWNLOAD-FROM-ALLOW-LIST=
API-DOWNLOAD-FROM-DENY-LIST=
API-DOWNLOAD-FROM-FROM-MAX-RETRY=4
API-DISABLE-DOWNLOAD-FROM=false
API_DISABLE_HEALTH_CHECK_LOGGING=false
API_DOWNLOAD_FROM_ALLOW_LIST=
API_DOWNLOAD_FROM_DENY_LIST=
API_DOWNLOAD_FROM_MAX_RETRY=4
API_DISABLE_DOWNLOAD_FROM=false
API_DISABLE_HEALTH_CHECK_ROUTE_TELEMETRY=false
API_DISABLE_ROOT_ROUTE_TELEMETRY=false
API_DISABLE_VERSION_ROUTE_TELEMETRY=false
API_DISABLE_DEBUG_ROUTE_TELEMETRY=false
API_ENABLE_DEBUG_ROUTE=false
CHROMIUM_RESTART_AFTER=10
CHROMIUM_RESTART_AFTER=100
CHROMIUM_MAX_QUEUE_SIZE=0
CHROMIUM_MAX_CONCURRENCY=6
CHROMIUM_AUTO_START=false
CHROMIUM_START_TIMEOUT=20s
CHROMIUM_INCOGNITO=false
CHROMIUM_ALLOW_INSECURE_LOCALHOST=false
CHROMIUM_IGNORE_CERTIFICATE_ERRORS=false
CHROMIUM_DISABLE_WEB_SECURITY=false
@@ -52,20 +57,26 @@ LIBREOFFICE_AUTO_START=false
LIBREOFFICE_START_TIMEOUT=20s
LIBREOFFICE_DISABLE_ROUTES=false
LOG_LEVEL=info
LOG_FORMAT=auto
LOG_FIELDS_PREFIX=
LOG_ENABLE_GCP_FIELDS=false
LOG_STD_FORMAT=auto
LOG_STD_ENABLE_GCP_FIELDS=false
PDFENGINES_MERGE_ENGINES=qpdf,pdfcpu,pdftk
PDFENGINES_SPLIT_ENGINES=pdfcpu,qpdf,pdftk
PDFENGINES_FLATTEN_ENGINES=qpdf
PDFENGINES_CONVERT_ENGINES=libreoffice-pdfengine
PDFENGINES_READ_METADATA_ENGINES=exiftool
PDFENGINES_WRITE_METADATA_ENGINES=exiftool
PDFENGINES_ENCRYPT_ENGINES=qpdf,pdfcpu,pdftk
PDFENGINES_DISABLE_ROUTES=false
PROMETHEUS_NAMESPACE=gotenberg
PROMETHEUS_COLLECT_INTERVAL=1s
PROMETHEUS_DISABLE_ROUTE_LOGGING=false
PROMETHEUS_DISABLE_COLLECT=false
PDFENGINES_ADD_ATTACHMENTS_ENGINES=pdfcpu
OTEL_SERVICE_NAME=gotenberg
OTEL_TRACES_EXPORTER=none
OTEL_METRICS_EXPORTER=none
OTEL_LOGS_EXPORTER=none
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_EXPORTER_OTLP_INSECURE=true
WEBHOOK_ENABLE_SYNC_MODE=false
WEBHOOK_ALLOW_LIST=
WEBHOOK_DENY_LIST=
WEBHOOK_ERROR_ALLOW_LIST=
@@ -76,77 +87,20 @@ WEBHOOK_RETRY_MAX_WAIT=30s
WEBHOOK_CLIENT_TIMEOUT=30s
WEBHOOK_DISABLE=false
# Export all variables so they are available to Compose
export
.PHONY: run
run: ## Start a Gotenberg container
docker run --rm -it \
-p $(API_PORT):$(API_PORT) \
-e GOTENBERG_API_BASIC_AUTH_USERNAME=$(GOTENBERG_API_BASIC_AUTH_USERNAME) \
-e GOTENBERG_API_BASIC_AUTH_PASSWORD=$(GOTENBERG_API_BASIC_AUTH_PASSWORD) \
$(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY):$(GOTENBERG_VERSION) \
gotenberg \
--gotenberg-graceful-shutdown-duration=$(GOTENBERG_GRACEFUL_SHUTDOWN_DURATION) \
--gotenberg-build-debug-data="$(GOTENBERG_BUILD_DEBUG_DATA)" \
--api-port=$(API_PORT) \
--api-port-from-env=$(API_PORT_FROM_ENV) \
--api-bind-ip=$(API_BIND_IP) \
--api-start-timeout=$(API_START_TIMEOUT) \
--api-timeout=$(API_TIMEOUT) \
--api-body-limit="$(API_BODY_LIMIT)" \
--api-root-path=$(API_ROOT_PATH) \
--api-trace-header=$(API_TRACE_HEADER) \
--api-enable-basic-auth=$(API_ENABLE_BASIC_AUTH) \
--api-download-from-allow-list=$(API-DOWNLOAD-FROM-ALLOW-LIST) \
--api-download-from-deny-list=$(API-DOWNLOAD-FROM-DENY-LIST) \
--api-download-from-max-retry=$(API-DOWNLOAD-FROM-FROM-MAX-RETRY) \
--api-disable-download-from=$(API-DISABLE-DOWNLOAD-FROM) \
--api-disable-health-check-logging=$(API_DISABLE_HEALTH_CHECK_LOGGING) \
--api-enable-debug-route=$(API_ENABLE_DEBUG_ROUTE) \
--chromium-restart-after=$(CHROMIUM_RESTART_AFTER) \
--chromium-auto-start=$(CHROMIUM_AUTO_START) \
--chromium-max-queue-size=$(CHROMIUM_MAX_QUEUE_SIZE) \
--chromium-start-timeout=$(CHROMIUM_START_TIMEOUT) \
--chromium-incognito=$(CHROMIUM_INCOGNITO) \
--chromium-allow-insecure-localhost=$(CHROMIUM_ALLOW_INSECURE_LOCALHOST) \
--chromium-ignore-certificate-errors=$(CHROMIUM_IGNORE_CERTIFICATE_ERRORS) \
--chromium-disable-web-security=$(CHROMIUM_DISABLE_WEB_SECURITY) \
--chromium-allow-file-access-from-files=$(CHROMIUM_ALLOW_FILE_ACCESS_FROM_FILES) \
--chromium-host-resolver-rules=$(CHROMIUM_HOST_RESOLVER_RULES) \
--chromium-proxy-server=$(CHROMIUM_PROXY_SERVER) \
--chromium-allow-list="$(CHROMIUM_ALLOW_LIST)" \
--chromium-deny-list="$(CHROMIUM_DENY_LIST)" \
--chromium-clear-cache=$(CHROMIUM_CLEAR_CACHE) \
--chromium-clear-cookies=$(CHROMIUM_CLEAR_COOKIES) \
--chromium-disable-javascript=$(CHROMIUM_DISABLE_JAVASCRIPT) \
--chromium-disable-routes=$(CHROMIUM_DISABLE_ROUTES) \
--libreoffice-restart-after=$(LIBREOFFICE_RESTART_AFTER) \
--libreoffice-max-queue-size=$(LIBREOFFICE_MAX_QUEUE_SIZE) \
--libreoffice-auto-start=$(LIBREOFFICE_AUTO_START) \
--libreoffice-start-timeout=$(LIBREOFFICE_START_TIMEOUT) \
--libreoffice-disable-routes=$(LIBREOFFICE_DISABLE_ROUTES) \
--log-level=$(LOG_LEVEL) \
--log-format=$(LOG_FORMAT) \
--log-fields-prefix=$(LOG_FIELDS_PREFIX) \
--log-enable-gcp-fields=$(LOG_ENABLE_GCP_FIELDS) \
--pdfengines-merge-engines=$(PDFENGINES_MERGE_ENGINES) \
--pdfengines-split-engines=$(PDFENGINES_SPLIT_ENGINES) \
--pdfengines-flatten-engines=$(PDFENGINES_FLATTEN_ENGINES) \
--pdfengines-convert-engines=$(PDFENGINES_CONVERT_ENGINES) \
--pdfengines-read-metadata-engines=$(PDFENGINES_READ_METADATA_ENGINES) \
--pdfengines-write-metadata-engines=$(PDFENGINES_WRITE_METADATA_ENGINES) \
--pdfengines-disable-routes=$(PDFENGINES_DISABLE_ROUTES) \
--prometheus-namespace=$(PROMETHEUS_NAMESPACE) \
--prometheus-collect-interval=$(PROMETHEUS_COLLECT_INTERVAL) \
--prometheus-disable-route-logging=$(PROMETHEUS_DISABLE_ROUTE_LOGGING) \
--prometheus-disable-collect=$(PROMETHEUS_DISABLE_COLLECT) \
--webhook-allow-list="$(WEBHOOK_ALLOW_LIST)" \
--webhook-deny-list="$(WEBHOOK_DENY_LIST)" \
--webhook-error-allow-list=$(WEBHOOK_ERROR_ALLOW_LIST) \
--webhook-error-deny-list=$(WEBHOOK_ERROR_DENY_LIST) \
--webhook-max-retry=$(WEBHOOK_MAX_RETRY) \
--webhook-retry-min-wait=$(WEBHOOK_RETRY_MIN_WAIT) \
--webhook-retry-max-wait=$(WEBHOOK_RETRY_MAX_WAIT) \
--webhook-client-timeout=$(WEBHOOK_CLIENT_TIMEOUT) \
--webhook-disable=$(WEBHOOK_DISABLE)
run: ## Start a Gotenberg container via Compose
docker compose up gotenberg
.PHONY: telemetry
telemetry: ## Start an OpenTelemetry collector and OpenObserve containers via Compose
docker compose up otel-collector openobserve
.PHONY: down
down: ## Stop all containers
docker compose down -v
.PHONY: test-unit
test-unit: ## Run unit tests
@@ -154,14 +108,46 @@ test-unit: ## Run unit tests
PLATFORM=
NO_CONCURRENCY=false
# Available tags:
# chromium
# chromium-concurrent
# chromium-convert-html
# chromium-convert-markdown
# chromium-convert-url
# debug
# health
# libreoffice
# libreoffice-convert
# output-filename
# pdfengines
# pdfengines-convert
# pdfengines-attachments
# attachments
# pdfengines-encrypt
# encrypt
# pdfengines-flatten
# flatten
# pdfengines-merge
# merge
# pdfengines-metadata
# metadata
# pdfengines-split
# split
# root
# version
# webhook
# download-from
# telemetry
TAGS=
.PHONY: test-integration
test-integration: ## Run integration tests
go test -timeout 20m -tags=integration -v github.com/gotenberg/gotenberg/v8/test/integration -args \
go test -timeout 40m -tags=integration -v github.com/gotenberg/gotenberg/v8/test/integration -args \
--gotenberg-docker-repository=$(DOCKER_REPOSITORY) \
--gotenberg-version=$(GOTENBERG_VERSION) \
--gotenberg-container-platform=$(PLATFORM) \
--no-concurrency=$(NO_CONCURRENCY)
--no-concurrency=$(NO_CONCURRENCY) \
--tags="$(TAGS)"
.PHONY: lint
lint: ## Lint Golang codebase
@@ -177,6 +163,7 @@ lint-todo: ## Find TODOs in Golang codebase
.PHONY: fmt
fmt: ## Format Golang codebase and "optimize" the dependencies
go fix ./...
golangci-lint fmt
go mod tidy

View File

@@ -4,48 +4,46 @@
<p align="center">A containerized API for seamless PDF conversion</p>
<p align="center">
<a href="https://hub.docker.com/r/gotenberg/gotenberg"><img alt="Total downloads (gotenberg/gotenberg)" src="https://img.shields.io/docker/pulls/gotenberg/gotenberg"></a>
<a href="https://hub.docker.com/r/thecodingmachine/gotenberg"><img alt="Total downloads (thecodingmachine/gotenberg)" src="https://img.shields.io/docker/pulls/thecodingmachine/gotenberg"></a>
<a href="https://github.com/gotenberg/gotenberg/actions/workflows/continuous-integration.yml"><img alt="Continuous Integration" src="https://github.com/gotenberg/gotenberg/actions/workflows/continuous-integration.yml/badge.svg"></a>
<a href="https://pkg.go.dev/github.com/gotenberg/gotenberg/v8"><img alt="Go Reference" src="https://pkg.go.dev/badge/github.com/gotenberg/gotenberg.svg"></a>
</p>
<p align="center">
<a href="https://trendshift.io/repositories/2996"><img src="https://trendshift.io/api/badge/repositories/2996" alt="gotenberg%2Fgotenberg | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</p>
<p align="center"><a href="https://gotenberg.dev/docs/getting-started/introduction">Documentation</a> &#183; <a href="https://gotenberg.dev/docs/getting-started/installation#live-demo-">Live Demo</a> 🔥</p>
<p align="center"><a href="https://gotenberg.dev/docs/getting-started/introduction">Read the Documentation</a> &#183; <a href="https://gotenberg.dev/docs/getting-started/installation#live-demo-">Try the Live Demo</a> 🔥</p>
</p>
---
**Gotenberg** provides a developer-friendly API to interact with powerful tools like Chromium and LibreOffice for converting
numerous document formats (HTML, Markdown, Word, Excel, etc.) into PDF files, and more!
**Gotenberg** is a containerized API that abstracts the complexity of PDF conversion.
It provides a `multipart/form-data` interface for interacting with powerful engines like Chromium and LibreOffice.
Instead of managing heavy dependencies, browser versions, or fonts in your own backend, simply send your files to
Gotenberg and get a PDF in return.
## Quick Start
Open a terminal and run the following command:
```
```bash
docker run --rm -p 3000:3000 gotenberg/gotenberg:8
```
Alternatively, using the historic Docker repository from our sponsor [TheCodingMachine](https://www.thecodingmachine.com):
```
docker run --rm -p 3000:3000 thecodingmachine/gotenberg:8
```
The API is now available on your host at http://localhost:3000.
Head to the [documentation](https://gotenberg.dev/docs/getting-started/introduction) to learn how to interact with it 🚀
With the API running at `http://localhost:3000`, you are now ready to head
to the **[Full Documentation](https://gotenberg.dev/docs/getting-started/introduction)** to discover how to convert URLs,
local files, inject custom CSS, merge PDFs, and more.
## Sponsors
<p align="center">
<a href="https://thecodingmachine.com">
<img src="https://user-images.githubusercontent.com/8983173/130324668-9d6e7b35-53a3-49c7-a574-38190d2bd6b0.png" alt="TheCodingMachine Logo" width="333" height="163" />
</a>
<a href="https://pdfme.com?utm_source=gotenberg_github&utm_medium=website" target="_blank">
<img src="https://github.com/user-attachments/assets/2a75dd40-ca18-4d34-acd5-5dd474595168" alt="pdfme Logo" width="333" height="163" />
</a>
</p>
Open-source development takes a significant amount of time, energy, and dedication. If Gotenberg helps streamline your
workflow or powers your business, please consider supporting its continuous improvement by [**becoming a sponsor**](https://github.com/sponsors/gulien)! ❤️
Sponsorships help maintain and improve Gotenberg - [become a sponsor](https://github.com/sponsors/gulien) ❤️
**Historic & GitHub Sponsors**
- [TheCodingMachine](https://thecodingmachine.com/)
- [pdfme](https://pdfme.com/)
**Powered By**
- [Docker](https://docs.docker.com/docker-hub/repos/manage/trusted-content/dsos-program/)
- [JetBrains](https://www.jetbrains.com/community/opensource/)

View File

@@ -1,7 +1,7 @@
# ARG instructions do not create additional layers. Instead, next layers will
# concatenate them. Also, we have to repeat ARG instructions in each build
# stage that uses them.
ARG GOLANG_VERSION=1.24
ARG GOLANG_VERSION=1.26.0
# ----------------------------------------------
# pdfcpu binary build stage
@@ -11,7 +11,7 @@ ARG GOLANG_VERSION=1.24
FROM golang:$GOLANG_VERSION AS pdfcpu-binary-stage
# See https://github.com/pdfcpu/pdfcpu/releases.
ARG PDFCPU_VERSION=v0.8.1
ARG PDFCPU_VERSION=v0.11.1
ENV CGO_ENABLED=0
# Define the working directory outside of $GOPATH (we're using go modules).
@@ -51,29 +51,11 @@ COPY pkg ./pkg
RUN go build -o gotenberg -ldflags "-s -w -X 'github.com/gotenberg/gotenberg/v8/cmd.Version=$GOTENBERG_VERSION'" cmd/gotenberg/main.go
# ----------------------------------------------
# Compress Golang binaries stage
# ----------------------------------------------
FROM debian:12-slim AS compress-go-binaries-stage
RUN \
echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/sources.list &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t bookworm-backports upx-ucl
COPY --from=pdfcpu-binary-stage /home/pdfcpu /home/pdfcpu
COPY --from=gotenberg-binary-stage /home/gotenberg /home/gotenberg
RUN \
upx-ucl --best /home/pdfcpu &&\
upx-ucl --best /home/gotenberg
# ----------------------------------------------
# Custom JRE stage
# Credits: https://github.com/jodconverter/docker-image-jodconverter-runtime
# ----------------------------------------------
FROM debian:12-slim AS custom-jre-stage
FROM debian:13-slim AS custom-jre-stage
RUN \
apt-get update -qq &&\
@@ -82,7 +64,7 @@ RUN \
# Note: jdeps helps finding which modules a JAR requires.
# Currently only for PDFtk, as we don't rely on LibreOffice UNO Java SDK.
ENV JAVA_MODULES=java.base,java.desktop,java.naming,java.sql
ENV JAVA_MODULES=java.base,java.desktop,java.xml
RUN jlink \
--add-modules $JAVA_MODULES \
@@ -92,12 +74,40 @@ RUN jlink \
--compress=2 \
--output /custom-jre
# ----------------------------------------------
# Downloader stage
# ----------------------------------------------
FROM debian:13-slim AS downloader-stage
# See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
ARG PDFTK_VERSION=v3.3.3
RUN apt-get update -qq && \
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends curl ca-certificates
WORKDIR /downloads
RUN curl -Ls https://raw.githubusercontent.com/gotenberg/unoconverter/v0.2.0/unoconv -o unoconverter &&\
chmod +x unoconverter
RUN curl -o pdftk-all.jar "https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/$PDFTK_VERSION/pdftk-all.jar" &&\
chmod a+x pdftk-all.jar
# ----------------------------------------------
# Base image stage
# ----------------------------------------------
FROM debian:12-slim AS base-image-stage
FROM debian:13-slim AS base-image-stage
COPY --from=custom-jre-stage /custom-jre /opt/java
ARG TIMEZONE=UTC
ENV TZ=$TIMEZONE
# Set default characterset encoding to UTF-8.
# See:
# https://github.com/gotenberg/gotenberg/issues/104
# https://github.com/gotenberg/gotenberg/issues/730
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
COPY --link --from=custom-jre-stage /custom-jre /opt/java
ENV PATH="/opt/java/bin:${PATH}"
@@ -109,10 +119,6 @@ FROM base-image-stage
ARG GOTENBERG_VERSION=snapshot
ARG GOTENBERG_USER_GID=1001
ARG GOTENBERG_USER_UID=1001
# See https://github.com/googlefonts/noto-emoji/releases.
ARG NOTO_COLOR_EMOJI_VERSION=v2.047
# See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
ARG PDFTK_VERSION=v3.3.3
LABEL org.opencontainers.image.title="Gotenberg" \
org.opencontainers.image.description="A containerized API for seamless PDF conversion." \
@@ -130,133 +136,55 @@ RUN \
chown gotenberg: /home/gotenberg
RUN \
# Install system dependencies required for the next instructions or debugging.
echo "deb http://deb.debian.org/debian trixie-backports main" >> /etc/apt/sources.list &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
# Note: tini is a helper for reaping zombie processes.
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends curl gnupg=2.2.40-1.1 tini=0.19.0-1 python3=3.11.2-1+b1 &&\
# Cleanup.
# Note: the Debian image does automatically a clean after each install thanks to a hook.
# Therefore, there is no need for apt-get clean.
# See https://stackoverflow.com/a/24417119/3248473.
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN \
# Install fonts.
# Credits:
# https://github.com/arachnys/athenapdf/blob/master/cli/Dockerfile.
# https://help.accusoft.com/PrizmDoc/v12.1/HTML/Installing_Asian_Fonts_on_Ubuntu_and_Debian.html.
curl -o ./ttf-mscorefonts-installer_3.8.1_all.deb http://httpredir.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.8.1_all.deb &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \
./ttf-mscorefonts-installer_3.8.1_all.deb \
culmus=0.133-1 \
fonts-beng=2:1.3 \
fonts-hosny-amiri=0.113-1 \
fonts-lklug-sinhala=0.6-4 \
fonts-lohit-guru=2.91.2-3 \
fonts-lohit-knda=2.5.4-3 \
fonts-samyak-gujr=1.2.2-6 \
fonts-samyak-mlym=1.2.2-6 \
fonts-samyak-taml=1.2.2-6 \
fonts-sarai=1.0-3 \
fonts-sil-abyssinica=2.100-3 \
fonts-sil-padauk=5.000-3 \
fonts-telu=2:1.3 \
fonts-thai-tlwg=1:0.7.3-1 \
ttf-wqy-zenhei \
fonts-arphic-ukai=0.2.20080216.2-5 \
fonts-arphic-uming=0.2.20080216.2-11 \
fonts-ipafont-mincho=00303-23 \
fonts-ipafont-gothic=00303-23 \
fonts-unfonts-core=1:1.0.2-080608-18 \
# LibreOffice recommends.
fonts-crosextra-caladea=20200211-1 \
fonts-crosextra-carlito=20220224-1 \
fonts-dejavu=2.37-6 \
fonts-liberation=1:1.07.4-11 \
fonts-liberation2=2.1.5-1 \
fonts-linuxlibertine=5.3.0-6 \
fonts-noto-cjk=1:20220127+repack1-1 \
fonts-noto-core=20201225-1 \
fonts-noto-mono=20201225-1 \
fonts-noto-ui-core=20201225-1 \
fonts-sil-gentium=20081126:1.03-4 \
fonts-sil-gentium-basic=1.102-1.1 &&\
rm -f ./ttf-mscorefonts-installer_3.8.1_all.deb &&\
# Add Color and Black-and-White Noto emoji font.
# Credits:
# https://github.com/gotenberg/gotenberg/pull/325.
# https://github.com/googlefonts/noto-emoji.
curl -Ls "https://github.com/googlefonts/noto-emoji/raw/$NOTO_COLOR_EMOJI_VERSION/fonts/NotoColorEmoji.ttf" -o /usr/local/share/fonts/NotoColorEmoji.ttf &&\
# Cleanup.
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN \
# Install either Google Chrome stable on amd64 architecture or
# Chromium on other architectures.
# See https://github.com/gotenberg/gotenberg/issues/328.
/bin/bash -c \
'set -e &&\
if [[ "$(dpkg --print-architecture)" == "amd64" ]]; then \
curl https://dl.google.com/linux/linux_signing_key.pub | apt-key add - &&\
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google-chrome.list &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends --allow-unauthenticated google-chrome-stable &&\
mv /usr/bin/google-chrome-stable /usr/bin/chromium; \
else \
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends chromium; \
fi' &&\
# Verify installation.
chromium --version &&\
# Cleanup.
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set default characterset encoding to UTF-8.
# See:
# https://github.com/gotenberg/gotenberg/issues/104
# https://github.com/gotenberg/gotenberg/issues/730
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
RUN \
tini python3 python3-distutils-extra \
# Install fonts.
# Essential metric-compatible fonts for LibreOffice layout fidelity (replaces MS Fonts).
fonts-crosextra-carlito \
fonts-crosextra-caladea \
fonts-liberation \
fonts-liberation2 \
# Reliable general-purpose fallback for Chromium.
fonts-dejavu \
# Unified CJK (Chinese, Japanese, Korean) support.
fonts-noto-cjk \
# Standard Emoji support.
fonts-noto-color-emoji \
# Install Hyphenation for LibreOffice.
# Credits: https://wiki.archlinux.org/title/LibreOffice.
hyphen-af hyphen-as hyphen-be hyphen-bg hyphen-bn hyphen-ca hyphen-cs hyphen-da hyphen-de hyphen-el \
hyphen-en-gb hyphen-en-us hyphen-eo hyphen-es hyphen-fr hyphen-gl hyphen-gu hyphen-hi hyphen-hr hyphen-hu \
hyphen-id hyphen-is hyphen-it hyphen-kn hyphen-lt hyphen-lv hyphen-ml hyphen-mn hyphen-mr hyphen-nl \
hyphen-no hyphen-or hyphen-pa hyphen-pl hyphen-pt-br hyphen-pt-pt hyphen-ro hyphen-ru hyphen-sk hyphen-sl \
hyphen-sr hyphen-sv hyphen-ta hyphen-te hyphen-th hyphen-uk hyphen-zu \
# Install Chromium.
chromium \
# Install QPDF & ExifTool (PDF engines).
qpdf exiftool &&\
# Install LibreOffice & unoconverter.
echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/sources.list &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t bookworm-backports libreoffice &&\
curl -Ls https://raw.githubusercontent.com/gotenberg/unoconverter/v0.1.1/unoconv -o /usr/bin/unoconverter &&\
chmod +x /usr/bin/unoconverter &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t trixie-backports \
libreoffice-writer libreoffice-calc libreoffice-impress libreoffice-draw python3-uno &&\
# unoconverter will look for the Python binary, which has to be at version 3.
ln -s /usr/bin/python3 /usr/bin/python &&\
# Verify installations.
libreoffice --version &&\
unoconverter --version &&\
# Cleanup.
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN \
# Install PDFtk, QPDF & ExifTool (PDF engines).
# See https://github.com/gotenberg/gotenberg/pull/273.
curl -o /usr/bin/pdftk-all.jar "https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/$PDFTK_VERSION/pdftk-all.jar" &&\
chmod a+x /usr/bin/pdftk-all.jar &&\
printf '#!/bin/bash\n\nexec java -jar /usr/bin/pdftk-all.jar "$@"' > /usr/bin/pdftk && \
chmod +x /usr/bin/pdftk &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends qpdf=11.3.0-1+deb12u1 exiftool &&\
# See https://github.com/nextcloud/docker/issues/380.
mkdir -p /usr/share/man/man1 &&\
# Verify installations.
pdftk --version &&\
qpdf --version &&\
exiftool --version &&\
# Cleanup.
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
apt-get autoremove -yqq &&\
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* /usr/share/man/* /usr/share/info/*
# Copy downloaded artifacts (unoconverter & PDFtk).
COPY --link --from=downloader-stage /downloads/unoconverter /usr/bin/unoconverter
COPY --link --from=downloader-stage /downloads/pdftk-all.jar /usr/bin/pdftk-all.jar
RUN \
# Install PDFtk bash wrapper.
# See https://github.com/gotenberg/gotenberg/pull/273.
printf '#!/bin/bash\n\nexec java -jar /usr/bin/pdftk-all.jar "$@"' > /usr/bin/pdftk && \
chmod +x /usr/bin/pdftk
# Support for arbitrary user IDs (OpenShift).
# See:
@@ -271,14 +199,19 @@ RUN \
# Credits:
# https://github.com/arachnys/athenapdf/issues/69.
# https://github.com/arachnys/athenapdf/commit/ba25a8d80a25d08d58865519c4cd8756dc9a336d.
COPY build/fonts.conf /etc/fonts/conf.d/100-gotenberg.conf
COPY --link build/fonts.conf /etc/fonts/conf.d/100-gotenberg.conf
# Copy dictionnaries so that hypens work on Chromium.
# See https://github.com/gotenberg/gotenberg/issues/1293.
COPY --link --chown="$GOTENBERG_USER_UID:$GOTENBERG_USER_GID" build/chromium-hyphen-data /opt/gotenberg/chromium-hyphen-data
# Copy the Golang binaries.
COPY --from=compress-go-binaries-stage /home/pdfcpu /usr/bin/
COPY --from=compress-go-binaries-stage /home/gotenberg /usr/bin/
COPY --link --from=pdfcpu-binary-stage /home/pdfcpu /usr/bin/
COPY --link --from=gotenberg-binary-stage /home/gotenberg /usr/bin/
# Environment variables required by modules or else.
ENV CHROMIUM_BIN_PATH=/usr/bin/chromium
ENV CHROMIUM_HYPHEN_DATA_DIR_PATH=/opt/gotenberg/chromium-hyphen-data
ENV LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin
ENV UNOCONVERTER_BIN_PATH=/usr/bin/unoconverter
ENV PDFTK_BIN_PATH=/usr/bin/pdftk
@@ -293,4 +226,4 @@ WORKDIR /home/gotenberg
EXPOSE 3000
ENTRYPOINT [ "/usr/bin/tini", "--" ]
CMD [ "gotenberg" ]
CMD [ "gotenberg" ]

View File

@@ -0,0 +1,21 @@
ARG DOCKER_REGISTRY
ARG DOCKER_REPOSITORY
ARG GOTENBERG_VERSION
FROM $DOCKER_REGISTRY/$DOCKER_REPOSITORY:$GOTENBERG_VERSION
USER root
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.1 /lambda-adapter /opt/extensions/lambda-adapter
# AWS.
ENV AWS_LWA_PORT=3000
ENV AWS_LWA_READINESS_CHECK_PATH=/health
ENV AWS_LWA_INVOKE_MODE=buffered
# Gotenberg.
ENV API_PORT_FROM_ENV=AWS_LWA_PORT
ENV WEBHOOK_ENABLE_SYNC_MODE=true
ENV GOTENBERG_BUILD_DEBUG_DATA=false
USER gotenberg

View File

@@ -11,4 +11,12 @@ USER root
# See https://github.com/gotenberg/gotenberg/issues/90#issuecomment-543551353.
RUN chown gotenberg: /usr/bin/tini
# Gotenberg.
ENV API_PORT_FROM_ENV=PORT
ENV CHROMIUM_AUTO_START=true
ENV LIBREOFFICE_AUTO_START=true
ENV WEBHOOK_ENABLE_SYNC_MODE=true
ENV GOTENBERG_BUILD_DEBUG_DATA=false
ENV LOG_ENABLE_GCP_FIELDS=true
USER gotenberg

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
{
"manifest_version": 2,
"name": "hyphens-data",
"version": "120.0.6050.0"
}

View File

@@ -36,23 +36,25 @@ var Version = "snapshot"
// Run starts the Gotenberg application. Call this in the main of your program.
func Run() {
fmt.Printf(banner, Version)
gotenberg.Version = Version
// Create the root FlagSet and adds the modules flags to it.
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
fs.Bool("gotenberg-hide-banner", false, "Hide the banner")
fs.Duration("gotenberg-graceful-shutdown-duration", time.Duration(30)*time.Second, "Set the graceful shutdown duration")
fs.Bool("gotenberg-build-debug-data", true, "Set if build data is needed")
fs.String("log-level", gotenberg.InfoLoggingLevel, fmt.Sprintf("Choose the level of logging detail. Options include %s, %s, %s, or %s", gotenberg.ErrorLoggingLevel, gotenberg.WarnLoggingLevel, gotenberg.InfoLoggingLevel, gotenberg.DebugLoggingLevel))
fs.String("log-fields-prefix", "", "Prepend a specified prefix to each field in the logs")
fs.String("log-std-format", gotenberg.AutoLoggingFormat, fmt.Sprintf("Specify the format of standard logging. Options include %s, %s, or %s", gotenberg.AutoLoggingFormat, gotenberg.JsonLoggingFormat, gotenberg.TextLoggingFormat))
fs.Bool("log-std-enable-gcp-fields", false, "Enable Google Cloud Platform fields for standard logging - namely: time, message, severity")
descriptors := gotenberg.GetModuleDescriptors()
var modsInfo string
var modsInfo strings.Builder
for _, desc := range descriptors {
fs.AddFlagSet(desc.FlagSet)
modsInfo += desc.ID + " "
modsInfo.WriteString(desc.ID + " ")
}
fmt.Printf("[SYSTEM] modules: %s\n", modsInfo)
// Parse the flags.
err := fs.Parse(os.Args[1:])
if err != nil {
@@ -90,13 +92,46 @@ func Run() {
// Create a wrapper around our flags.
parsedFlags := gotenberg.ParsedFlags{FlagSet: fs}
// Get the graceful shutdown duration.
hideBanner := parsedFlags.MustBool("gotenberg-hide-banner")
gracefulShutdownDuration := parsedFlags.MustDuration("gotenberg-graceful-shutdown-duration")
serviceName := os.Getenv("OTEL_SERVICE_NAME")
if serviceName == "" {
serviceName = "gotenberg"
}
telemetryConfig := gotenberg.TelemetryConfig{
// OpenTelemetry.
ServiceName: serviceName,
ServiceVersion: Version,
// Logging.
LogLevel: parsedFlags.MustString("log-level"),
LogFieldsPrefix: parsedFlags.MustString("log-fields-prefix"),
LogStdFormat: parsedFlags.MustDeprecatedString("log-format", "log-std-format"),
LogStdEnableGcpFields: parsedFlags.MustDeprecatedBool("log-enable-gcp-fields", "log-std-enable-gcp-fields"),
}
if !hideBanner {
fmt.Printf(banner, Version)
}
err = telemetryConfig.Validate()
if err != nil {
fmt.Printf("[FATAL] telemetry: %s\n", err)
os.Exit(1)
}
// Telemetry.
shutdownTelemetry, err := gotenberg.StartTelemetry(telemetryConfig)
if err != nil {
fmt.Printf("[FATAL] telemetry: %s\n", err)
os.Exit(1)
}
// Modules.
fmt.Printf("[SYSTEM] modules: %s\n", modsInfo.String())
ctx := gotenberg.NewContext(parsedFlags, descriptors)
// Start application modules.
apps, err := ctx.Modules(new(gotenberg.App))
if err != nil {
fmt.Printf("[FATAL] %s\n", err)
@@ -192,5 +227,12 @@ func Run() {
os.Exit(1)
}
err = shutdownTelemetry(gracefulShutdownCtx)
if err != nil {
fmt.Printf("[FATAL] telemetry: %v\n", err)
os.Exit(1)
}
fmt.Printf("[SYSTEM] telemetry: shutdown success\n")
os.Exit(0)
}

103
compose.yaml Normal file
View File

@@ -0,0 +1,103 @@
services:
gotenberg:
image: ${DOCKER_REGISTRY}/${DOCKER_REPOSITORY}:${GOTENBERG_VERSION}
ports:
- "${API_PORT}:${API_PORT}"
environment:
GOTENBERG_API_BASIC_AUTH_USERNAME: ${GOTENBERG_API_BASIC_AUTH_USERNAME}
GOTENBERG_API_BASIC_AUTH_PASSWORD: ${GOTENBERG_API_BASIC_AUTH_PASSWORD}
OTEL_SERVICE_NAME: ${OTEL_SERVICE_NAME}
OTEL_TRACES_EXPORTER: ${OTEL_TRACES_EXPORTER}
OTEL_METRICS_EXPORTER: ${OTEL_METRICS_EXPORTER}
OTEL_LOGS_EXPORTER: ${OTEL_LOGS_EXPORTER}
OTEL_EXPORTER_OTLP_PROTOCOL: ${OTEL_EXPORTER_OTLP_PROTOCOL}
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT}
OTEL_EXPORTER_OTLP_INSECURE: ${OTEL_EXPORTER_OTLP_INSECURE}
command:
- "gotenberg"
- "--gotenberg-hide-banner=${GOTENBERG_HIDE_BANNER}"
- "--gotenberg-graceful-shutdown-duration=${GOTENBERG_GRACEFUL_SHUTDOWN_DURATION}"
- "--gotenberg-build-debug-data=${GOTENBERG_BUILD_DEBUG_DATA}"
- "--api-port=${API_PORT}"
- "--api-port-from-env=${API_PORT_FROM_ENV}"
- "--api-bind-ip=${API_BIND_IP}"
- "--api-start-timeout=${API_START_TIMEOUT}"
- "--api-timeout=${API_TIMEOUT}"
- "--api-body-limit=${API_BODY_LIMIT}"
- "--api-root-path=${API_ROOT_PATH}"
- "--api-correlation-id-header=${API_CORRELATION_ID_HEADER}"
- "--api-enable-basic-auth=${API_ENABLE_BASIC_AUTH}"
- "--api-download-from-allow-list=${API_DOWNLOAD_FROM_ALLOW_LIST}"
- "--api-download-from-deny-list=${API_DOWNLOAD_FROM_DENY_LIST}"
- "--api-download-from-max-retry=${API_DOWNLOAD_FROM_MAX_RETRY}"
- "--api-disable-download-from=${API_DISABLE_DOWNLOAD_FROM}"
- "--api-disable-health-check-route-telemetry=${API_DISABLE_HEALTH_CHECK_ROUTE_TELEMETRY}"
- "--api-disable-root-route-telemetry=${API_DISABLE_ROOT_ROUTE_TELEMETRY}"
- "--api-disable-version-route-telemetry=${API_DISABLE_VERSION_ROUTE_TELEMETRY}"
- "--api-disable-debug-route-telemetry=${API_DISABLE_DEBUG_ROUTE_TELEMETRY}"
- "--api-enable-debug-route=${API_ENABLE_DEBUG_ROUTE}"
- "--chromium-restart-after=${CHROMIUM_RESTART_AFTER}"
- "--chromium-auto-start=${CHROMIUM_AUTO_START}"
- "--chromium-max-queue-size=${CHROMIUM_MAX_QUEUE_SIZE}"
- "--chromium-max-concurrency=${CHROMIUM_MAX_CONCURRENCY}"
- "--chromium-start-timeout=${CHROMIUM_START_TIMEOUT}"
- "--chromium-allow-insecure-localhost=${CHROMIUM_ALLOW_INSECURE_LOCALHOST}"
- "--chromium-ignore-certificate-errors=${CHROMIUM_IGNORE_CERTIFICATE_ERRORS}"
- "--chromium-disable-web-security=${CHROMIUM_DISABLE_WEB_SECURITY}"
- "--chromium-allow-file-access-from-files=${CHROMIUM_ALLOW_FILE_ACCESS_FROM_FILES}"
- "--chromium-host-resolver-rules=${CHROMIUM_HOST_RESOLVER_RULES}"
- "--chromium-proxy-server=${CHROMIUM_PROXY_SERVER}"
- "--chromium-allow-list=${CHROMIUM_ALLOW_LIST}"
- "--chromium-deny-list=${CHROMIUM_DENY_LIST}"
- "--chromium-clear-cache=${CHROMIUM_CLEAR_CACHE}"
- "--chromium-clear-cookies=${CHROMIUM_CLEAR_COOKIES}"
- "--chromium-disable-javascript=${CHROMIUM_DISABLE_JAVASCRIPT}"
- "--chromium-disable-routes=${CHROMIUM_DISABLE_ROUTES}"
- "--libreoffice-restart-after=${LIBREOFFICE_RESTART_AFTER}"
- "--libreoffice-max-queue-size=${LIBREOFFICE_MAX_QUEUE_SIZE}"
- "--libreoffice-auto-start=${LIBREOFFICE_AUTO_START}"
- "--libreoffice-start-timeout=${LIBREOFFICE_START_TIMEOUT}"
- "--libreoffice-disable-routes=${LIBREOFFICE_DISABLE_ROUTES}"
- "--log-level=${LOG_LEVEL}"
- "--log-fields-prefix=${LOG_FIELDS_PREFIX}"
- "--log-std-format=${LOG_STD_FORMAT}"
- "--log-std-enable-gcp-fields=${LOG_STD_ENABLE_GCP_FIELDS}"
- "--pdfengines-merge-engines=${PDFENGINES_MERGE_ENGINES}"
- "--pdfengines-split-engines=${PDFENGINES_SPLIT_ENGINES}"
- "--pdfengines-flatten-engines=${PDFENGINES_FLATTEN_ENGINES}"
- "--pdfengines-convert-engines=${PDFENGINES_CONVERT_ENGINES}"
- "--pdfengines-read-metadata-engines=${PDFENGINES_READ_METADATA_ENGINES}"
- "--pdfengines-write-metadata-engines=${PDFENGINES_WRITE_METADATA_ENGINES}"
- "--pdfengines-encrypt-engines=${PDFENGINES_ENCRYPT_ENGINES}"
- "--pdfengines-disable-routes=${PDFENGINES_DISABLE_ROUTES}"
- "--pdfengines-add-attachments-engines=${PDFENGINES_ADD_ATTACHMENTS_ENGINES}"
- "--webhook-enable-sync-mode=${WEBHOOK_ENABLE_SYNC_MODE}"
- "--webhook-allow-list=${WEBHOOK_ALLOW_LIST}"
- "--webhook-deny-list=${WEBHOOK_DENY_LIST}"
- "--webhook-error-allow-list=${WEBHOOK_ERROR_ALLOW_LIST}"
- "--webhook-error-deny-list=${WEBHOOK_ERROR_DENY_LIST}"
- "--webhook-max-retry=${WEBHOOK_MAX_RETRY}"
- "--webhook-retry-min-wait=${WEBHOOK_RETRY_MIN_WAIT}"
- "--webhook-retry-max-wait=${WEBHOOK_RETRY_MAX_WAIT}"
- "--webhook-client-timeout=${WEBHOOK_CLIENT_TIMEOUT}"
- "--webhook-disable=${WEBHOOK_DISABLE}"
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "4317:4317" # OTLP gRPC receiver
depends_on:
- openobserve
openobserve:
image: public.ecr.aws/zinclabs/openobserve:latest
restart: always
ports:
- "5080:5080"
- "5081:5081" # OTLP gRPC ingestion
environment:
ZO_ROOT_USER_EMAIL: telemetry@gotenberg.dev
ZO_ROOT_USER_PASSWORD: telemetry

154
go.mod
View File

@@ -1,58 +1,56 @@
module github.com/gotenberg/gotenberg/v8
go 1.24.0
go 1.26.0
require (
github.com/alexliesenfeld/health v0.8.0
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 // indirect
github.com/alexliesenfeld/health v0.8.1
github.com/barasher/go-exiftool v1.10.0
github.com/chromedp/cdproto v0.0.0-20250416210000-d7e4d624041a
github.com/chromedp/chromedp v0.13.6
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/labstack/echo/v4 v4.13.4
github.com/labstack/gommon v0.4.2
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/microcosm-cc/bluemonday v1.0.27
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/prometheus/client_golang v1.22.0
github.com/russross/blackfriday/v2 v2.1.0
github.com/spf13/pflag v1.0.6
github.com/ulikunitz/xz v0.5.12 // indirect
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.41.0
golang.org/x/sync v0.15.0
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0
golang.org/x/text v0.26.0
)
require (
github.com/cucumber/godog v0.15.0
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
github.com/chromedp/chromedp v0.14.2
github.com/cucumber/godog v0.15.1
github.com/dlclark/regexp2 v1.11.5
github.com/docker/docker v28.2.2+incompatible
github.com/docker/go-connections v0.5.0
github.com/mholt/archives v0.1.2
github.com/shirou/gopsutil/v4 v4.25.5
github.com/testcontainers/testcontainers-go v0.37.0
github.com/docker/docker v28.5.2+incompatible
github.com/docker/go-connections v0.6.0
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab
github.com/google/uuid v1.6.0
github.com/hashicorp/go-retryablehttp v0.7.8
github.com/labstack/echo/v4 v4.15.1
github.com/labstack/gommon v0.4.2
github.com/mholt/archives v0.1.5
github.com/microcosm-cc/bluemonday v1.0.27
github.com/shirou/gopsutil/v4 v4.26.1
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
github.com/testcontainers/testcontainers-go v0.40.0
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0
go.opentelemetry.io/otel v1.42.0
go.opentelemetry.io/otel/log v0.18.0
go.opentelemetry.io/otel/metric v1.42.0
go.opentelemetry.io/otel/sdk v1.42.0
go.opentelemetry.io/otel/sdk/log v0.18.0
go.opentelemetry.io/otel/sdk/metric v1.42.0
go.opentelemetry.io/otel/trace v1.42.0
go.uber.org/multierr v1.11.0
golang.org/x/net v0.51.0
golang.org/x/sync v0.19.0
golang.org/x/term v0.40.0
golang.org/x/text v0.34.0
)
require (
dario.cat/mergo v1.0.1 // indirect
dario.cat/mergo v1.0.2 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/STARRY-S/zip v0.2.3 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.0 // indirect
github.com/bodgit/sevenzip v1.6.1 // indirect
github.com/bodgit/windows v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
@@ -66,66 +64,84 @@ require (
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/ebitengine/purego v0.10.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-memdb v1.3.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
github.com/klauspost/compress v1.18.4 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/minio/minlz v1.0.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/minlz v1.0.1 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.1.0 // indirect
github.com/moby/go-archive v0.2.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/morikuni/aec v1.1.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nwaples/rardecode/v2 v2.1.1 // indirect
github.com/nwaples/rardecode/v2 v2.2.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pierrec/lz4/v4 v4.1.25 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/procfs v0.16.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sorairolake/lzip-go v0.3.7 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/otlptranslator v1.0.0 // indirect
github.com/prometheus/procfs v0.20.1 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/sorairolake/lzip-go v0.3.8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/time v0.11.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/protobuf v1.36.6 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go4.org v0.0.0-20260112195520-a5071408f32f // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/time v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
google.golang.org/grpc v1.79.2 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

537
go.sum
View File

@@ -1,36 +1,17 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=
github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=
github.com/alexliesenfeld/health v0.8.0 h1:lCV0i+ZJPTbqP7LfKG7p3qZBl5VhelwUFCIVWl77fgk=
github.com/alexliesenfeld/health v0.8.0/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc=
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 h1:8PmGpDEZl9yDpcdEr6Odf23feCxK3LNUNMxjXg41pZQ=
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/alexliesenfeld/health v0.8.1 h1:wdE3vt+cbJotiR8DGDBZPKHDFoJbAoWEfQTcqrmedUg=
github.com/alexliesenfeld/health v0.8.1/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/barasher/go-exiftool v1.10.0 h1:f5JY5jc42M7tzR6tbL9508S2IXdIcG9QyieEXNMpIhs=
@@ -39,25 +20,22 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A=
github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc=
github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=
github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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/chromedp/cdproto v0.0.0-20250416210000-d7e4d624041a h1:TVjyMfX22UgV/jP0A4UwrrCmI9zfvp6ZS5UBZMy3HDw=
github.com/chromedp/cdproto v0.0.0-20250416210000-d7e4d624041a/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
github.com/chromedp/chromedp v0.13.6 h1:xlNunMyzS5bu3r/QKrb3fzX6ow3WBQ6oao+J65PGZxk=
github.com/chromedp/chromedp v0.13.6/go.mod h1:h8GPP6ZtLMLsU8zFbTcb7ZDGCvCy8j/vRoFmRltQx9A=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZSzM=
github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
@@ -73,8 +51,8 @@ github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI=
github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0=
github.com/cucumber/godog v0.15.0 h1:51AL8lBXF3f0cyA5CV4TnJFCTHpgiy+1x1Hb3TtZUmo=
github.com/cucumber/godog v0.15.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces=
github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI=
github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8=
github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI=
github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s=
github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs=
@@ -85,30 +63,26 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY=
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 h1:vymEbVwYFP/L05h5TKQxvkXoKxNvTpjxYKdF1Nlwuao=
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -124,45 +98,19 @@ github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc=
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
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/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
@@ -173,33 +121,24 @@ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh
github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo=
github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -209,30 +148,32 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/echo/v4 v4.15.1 h1:S9keusg26gZpjMmPqB5hOEvNKnmd1lNmcHrbbH2lnFs=
github.com/labstack/echo/v4 v4.15.1/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM=
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mholt/archives v0.1.2 h1:UBSe5NfYKHI1sy+S5dJsEsG9jsKKk8NJA4HCC+xTI4A=
github.com/mholt/archives v0.1.2/go.mod h1:D7QzTHgw3ctfS6wgOO9dN+MFgdZpbksGCxprUOwZWDs=
github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ=
github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/minio/minlz v1.0.0 h1:Kj7aJZ1//LlTP1DM8Jm7lNKvvJS2m74gyyXXn3+uJWQ=
github.com/minio/minlz v1.0.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=
github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=
github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A=
github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
@@ -245,322 +186,174 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nwaples/rardecode/v2 v2.1.1 h1:OJaYalXdliBUXPmC8CZGQ7oZDxzX1/5mQmgn0/GASew=
github.com/nwaples/rardecode/v2 v2.1.1/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
github.com/nwaples/rardecode/v2 v2.2.2 h1:/5oL8dzYivRM/tqX9VcTSWfbpwcbwKG1QtSJr3b3KcU=
github.com/nwaples/rardecode/v2 v2.2.2/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sorairolake/lzip-go v0.3.7 h1:vP2uiD/NoklLyzYMdgOWkZME0ulkSfVTTE4MNRKCwNs=
github.com/sorairolake/lzip-go v0.3.7/go.mod h1:THOHr0FlNVCw2eOIEE9shFJAG1QxQg/pf2XUPAmNIqg=
github.com/shirou/gopsutil/v4 v4.26.1 h1:TOkEyriIXk2HX9d4isZJtbjXbEjf5qyKPAzbzY0JWSo=
github.com/shirou/gopsutil/v4 v4.26.1/go.mod h1:medLI9/UNAb0dOI9Q3/7yWSqKkj00u+1tgY8nvv41pc=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=
github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/testcontainers/testcontainers-go v0.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg=
github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
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/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
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/contrib/bridges/otelslog v0.15.0 h1:yOYhGNPZseueTTvWp5iBD3/CthrmvayUXYEX862dDi4=
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0/go.mod h1:CvaNVqIfcybc+7xqZNubbE+26K6P7AKZF/l0lE2kdCk=
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 h1:dkBzNEAIKADEaFnuESzcXvpd09vxvDZsOjx11gjUqLk=
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0/go.mod h1:Z5RIwRkZgauOIfnG5IpidvLpERjhTninpP1dTG2jTl4=
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 h1:4fnRcNpc6YFtG3zsFw9achKn3XgmxPxuMuqIL5rE8e8=
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0/go.mod h1:qTvIHMFKoxW7HXg02gm6/Wofhq5p3Ib/A/NNt1EoBSQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 h1:icqq3Z34UrEFk2u+HMhTtRsvo7Ues+eiJVjaJt62njs=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0/go.mod h1:W2m8P+d5Wn5kipj4/xmbt9uMqezEKfBjzVJadfABSBE=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 h1:H7O6RlGOMTizyl3R08Kn5pdM06bnH8oscSj7o11tmLA=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0/go.mod h1:mBFWu/WOVDkWWsR7Tx7h6EpQB8wsv7P0Yrh0Pb7othc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 h1:uLXP+3mghfMf7XmV4PkGfFhFKuNWoCvvx5wP/wOXo0o=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0/go.mod h1:v0Tj04armyT59mnURNUJf7RCKcKzq+lgJs6QSjHjaTc=
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 h1:g0LRDXMX/G1SEZtK8zl8Chm4K6GBwRkjPKE36LxiTYs=
go.opentelemetry.io/otel/exporters/prometheus v0.64.0/go.mod h1:UrgcjnarfdlBDP3GjDIJWe6HTprwSazNjwsI+Ru6hro=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 h1:KJVjPD3rcPb98rIs3HznyJlrfx9ge5oJvxxlGR+P/7s=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0/go.mod h1:K3kRa2ckmHWQaTWQdPRHc7qGXASuVuoEQXzrvlA98Ws=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 h1:lSZHgNHfbmQTPfuTmWVkEu8J8qXaQwuV30pjCcAUvP8=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0/go.mod h1:so9ounLcuoRDu033MW/E0AD4hhUjVqswrMF5FoZlBcw=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1JF26knRneorus8aOwVIDhvYx9WoDw=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs=
go.opentelemetry.io/otel/log v0.18.0 h1:XgeQIIBjZZrliksMEbcwMZefoOSMI1hdjiLEiiB0bAg=
go.opentelemetry.io/otel/log v0.18.0/go.mod h1:KEV1kad0NofR3ycsiDH4Yjcoj0+8206I6Ox2QYFSNgI=
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
go.opentelemetry.io/otel/sdk/log v0.18.0 h1:n8OyZr7t7otkeTnPTbDNom6rW16TBYGtvyy2Gk6buQw=
go.opentelemetry.io/otel/sdk/log v0.18.0/go.mod h1:C0+wxkTwKpOCZLrlJ3pewPiiQwpzycPI/u6W0Z9fuYk=
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0 h1:l3mYuPsuBx6UKE47BVcPrZoZ0q/KER57vbj2qkgDLXA=
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0/go.mod h1:7cHtiVJpZebB3wybTa4NG+FUo5NPe3PROz1FqB0+qdw=
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go4.org v0.0.0-20260112195520-a5071408f32f h1:ziUVAjmTPwQMBmYR1tbdRFJPtTcQUI12fH9QQjfb0Sw=
go4.org v0.0.0-20260112195520-a5071408f32f/go.mod h1:ZRJnO5ZI4zAwMFp+dS1+V6J6MSyAowhRqAE+DPa1Xp0=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
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.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
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-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -0,0 +1,32 @@
receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
processors:
batch:
exporters:
otlp/openobserve:
endpoint: "openobserve:5081"
tls:
insecure: true
headers:
Authorization: "Basic dGVsZW1ldHJ5QGdvdGVuYmVyZy5kZXY6dGVsZW1ldHJ5"
organization: "default"
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/openobserve]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp/openobserve]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlp/openobserve]

112
package-lock.json generated
View File

@@ -5,62 +5,32 @@
"packages": {
"": {
"devDependencies": {
"prettier": "3.5.3",
"prettier-plugin-gherkin": "^3.1.2",
"prettier-plugin-sh": "^0.17.4"
"prettier": "3.8.1",
"prettier-plugin-gherkin": "^3.1.3",
"prettier-plugin-sh": "^0.18.0"
}
},
"node_modules/@cucumber/gherkin": {
"version": "27.0.0",
"resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-27.0.0.tgz",
"integrity": "sha512-j5rCsjqzRiC3iVTier3sa0kzyNbkcAmF7xr7jKnyO7qDeK3Z8Ye1P3KSVpeQRMY+KCDJ3WbTDdyxH0FwfA/fIw==",
"version": "32.2.0",
"resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-32.2.0.tgz",
"integrity": "sha512-X8xuVhSIqlUjxSRifRJ7t0TycVWyX58fygJH3wDNmHINLg9sYEkvQT0SO2G5YlRZnYc11TIFr4YPenscvdlBIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cucumber/messages": ">=19.1.4 <=22"
}
},
"node_modules/@cucumber/gherkin/node_modules/@cucumber/messages": {
"version": "22.0.0",
"resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-22.0.0.tgz",
"integrity": "sha512-EuaUtYte9ilkxcKmfqGF9pJsHRUU0jwie5ukuZ/1NPTuHS1LxHPsGEODK17RPRbZHOFhqybNzG2rHAwThxEymg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/uuid": "9.0.1",
"class-transformer": "0.5.1",
"reflect-metadata": "0.1.13",
"uuid": "9.0.0"
}
},
"node_modules/@cucumber/gherkin/node_modules/@types/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==",
"dev": true,
"license": "MIT"
},
"node_modules/@cucumber/gherkin/node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"dev": true,
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
"@cucumber/messages": ">=19.1.4 <28"
}
},
"node_modules/@cucumber/messages": {
"version": "23.0.0",
"resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-23.0.0.tgz",
"integrity": "sha512-2ZWKNnikNMBnle3P3cgy+fgzhABrY4oBbiWp9wcI8ANdT4LlYRN6jQ6j/9CQGTDGRfkyRtr/5VkYq7q24XCsuA==",
"version": "27.2.0",
"resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-27.2.0.tgz",
"integrity": "sha512-f2o/HqKHgsqzFLdq6fAhfG1FNOQPdBdyMGpKwhb7hZqg0yZtx9BVqkTyuoNk83Fcvk3wjMVfouFXXHNEk4nddA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/uuid": "9.0.6",
"@types/uuid": "10.0.0",
"class-transformer": "0.5.1",
"reflect-metadata": "0.1.13",
"uuid": "9.0.1"
"reflect-metadata": "0.2.2",
"uuid": "11.0.5"
}
},
"node_modules/@reteps/dockerfmt": {
@@ -74,9 +44,9 @@
}
},
"node_modules/@types/uuid": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz",
"integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
"dev": true,
"license": "MIT"
},
@@ -88,9 +58,9 @@
"license": "MIT"
},
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
"dev": true,
"license": "MIT",
"bin": {
@@ -104,26 +74,26 @@
}
},
"node_modules/prettier-plugin-gherkin": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/prettier-plugin-gherkin/-/prettier-plugin-gherkin-3.1.2.tgz",
"integrity": "sha512-LgehRNKCAqZsoE/yblmqXYfMpEK2mhVWQKNj/TFzeLR+0rhFGHqq3RlYcYhPgzbr0n6w2Bv+0Gm1yxNdzkdacw==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/prettier-plugin-gherkin/-/prettier-plugin-gherkin-3.1.3.tgz",
"integrity": "sha512-w9uB413NlSi8ZQwpexyu+ttriJJ88eZLV0x88ZTkzkLZyHYEX5wrNtaCx/yFYviIu/tuwsBqDPM47VODnIV/hw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cucumber/gherkin": "^27.0.0",
"@cucumber/messages": "^23.0.0",
"prettier": "^3.0.0"
"@cucumber/gherkin": "^32.0.0",
"@cucumber/messages": "^27.2.0",
"prettier": "^3.5.3"
}
},
"node_modules/prettier-plugin-sh": {
"version": "0.17.4",
"resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.17.4.tgz",
"integrity": "sha512-aAVKXZ7GTEMZdZsIPSwMwddwPvt2ibMbRGd4OJAP0G7QoeYZV+mPNg2Oln3R53sZ4PVjeAA7Xzi/PuI0QlHHfQ==",
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.18.0.tgz",
"integrity": "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@reteps/dockerfmt": "^0.3.5",
"sh-syntax": "^0.5.6"
"@reteps/dockerfmt": "^0.3.6",
"sh-syntax": "^0.5.8"
},
"engines": {
"node": ">=16.0.0"
@@ -132,20 +102,20 @@
"url": "https://opencollective.com/unts"
},
"peerDependencies": {
"prettier": "^3.0.3"
"prettier": "^3.6.0"
}
},
"node_modules/reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/sh-syntax": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.5.7.tgz",
"integrity": "sha512-74m9dt91konrF5+m0kASugzi37VxKsnTJQ6yvdDZu3IijG5/vIZpImP6FadsJLWNt2X2YD0VaTwW5W7Ox7mFVg==",
"version": "0.5.8",
"resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.5.8.tgz",
"integrity": "sha512-JfVoxf4FxQI5qpsPbkHhZo+n6N9YMJobyl4oGEUBb/31oQYlgTjkXQD8PBiafS2UbWoxrTO0Z5PJUBXEPAG1Zw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -166,9 +136,9 @@
"license": "0BSD"
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz",
"integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==",
"dev": true,
"funding": [
"https://github.com/sponsors/broofa",
@@ -176,7 +146,7 @@
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
"uuid": "dist/esm/bin/uuid"
}
}
}

View File

@@ -1,7 +1,7 @@
{
"devDependencies": {
"prettier": "3.5.3",
"prettier-plugin-gherkin": "^3.1.2",
"prettier-plugin-sh": "^0.17.4"
"prettier": "3.8.1",
"prettier-plugin-gherkin": "^3.1.3",
"prettier-plugin-sh": "^0.18.0"
}
}

View File

@@ -6,17 +6,16 @@ import (
"errors"
"fmt"
"io"
"log/slog"
"os/exec"
"strings"
"syscall"
"go.uber.org/zap"
)
// Cmd wraps an [exec.Cmd].
type Cmd struct {
ctx context.Context
logger *zap.Logger
logger *slog.Logger
process *exec.Cmd
}
@@ -25,13 +24,13 @@ type Cmd struct {
// children without creating orphans.
//
// See https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773.
func Command(logger *zap.Logger, binPath string, args ...string) *Cmd {
func Command(logger *slog.Logger, binPath string, args ...string) *Cmd {
cmd := exec.Command(binPath, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
return &Cmd{
ctx: nil,
logger: logger.Named(strings.ReplaceAll(binPath, "/", "")),
logger: logger.With(slog.String("logger", strings.ReplaceAll(binPath, "/", ""))),
process: cmd,
}
}
@@ -41,7 +40,7 @@ func Command(logger *zap.Logger, binPath string, args ...string) *Cmd {
// children without creating orphans.
//
// See https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773.
func CommandContext(ctx context.Context, logger *zap.Logger, binPath string, args ...string) (*Cmd, error) {
func CommandContext(ctx context.Context, logger *slog.Logger, binPath string, args ...string) (*Cmd, error) {
if ctx == nil {
return nil, errors.New("nil context")
}
@@ -51,7 +50,7 @@ func CommandContext(ctx context.Context, logger *zap.Logger, binPath string, arg
return &Cmd{
ctx: ctx,
logger: logger.Named(strings.ReplaceAll(binPath, "/", "")),
logger: logger.With(slog.String("logger", strings.ReplaceAll(binPath, "/", ""))),
process: cmd,
}, nil
}
@@ -63,7 +62,7 @@ func (cmd *Cmd) Start() error {
return fmt.Errorf("pipe unix process output: %w", err)
}
cmd.logger.Debug(fmt.Sprintf("start unix process: %s", strings.Join(cmd.process.Args, " ")))
cmd.logger.DebugContext(cmd.ctx, fmt.Sprintf("start unix process: %s", strings.Join(cmd.process.Args, " ")))
err = cmd.process.Start()
if err != nil {
@@ -110,7 +109,7 @@ func (cmd *Cmd) Exec() (int, error) {
case err = <-errChan:
errProc := cmd.Kill()
if errProc != nil {
cmd.logger.Error(errProc.Error())
cmd.logger.ErrorContext(cmd.ctx, errProc.Error())
}
if err == nil {
@@ -125,7 +124,7 @@ func (cmd *Cmd) Exec() (int, error) {
case <-cmd.ctx.Done():
errProc := cmd.Kill()
if errProc != nil {
cmd.logger.Error(errProc.Error())
cmd.logger.ErrorContext(cmd.ctx, errProc.Error())
}
return 62, fmt.Errorf("context done: %w", cmd.ctx.Err())
@@ -135,8 +134,7 @@ func (cmd *Cmd) Exec() (int, error) {
// pipeOutput creates logs entries according to the process stdout and stderr.
// It does nothing if the logging level is not debug.
func (cmd *Cmd) pipeOutput() error {
checkedEntry := cmd.logger.Check(zap.DebugLevel, "check for debug level before piping unix process output")
if checkedEntry == nil {
if !cmd.logger.Enabled(cmd.ctx, slog.LevelDebug) {
return nil
}
@@ -152,12 +150,12 @@ func (cmd *Cmd) pipeOutput() error {
// logCommandOutput creates logs entries according to a reader
// (either stdout or stderr).
logCommandOutput := func(logger *zap.Logger, reader io.ReadCloser) {
logCommandOutput := func(logger *slog.Logger, reader io.ReadCloser) {
r := bufio.NewReader(reader)
defer func(reader io.ReadCloser) {
err := reader.Close()
if err != nil && !strings.Contains(err.Error(), "file already closed") {
logger.Error(fmt.Sprintf("close reader: %s", err))
logger.ErrorContext(cmd.ctx, fmt.Sprintf("close reader: %s", err))
}
}(reader)
@@ -165,20 +163,20 @@ func (cmd *Cmd) pipeOutput() error {
line, _, err := r.ReadLine()
if err != nil {
if err != io.EOF && !strings.Contains(err.Error(), "file already closed") {
logger.Error(fmt.Sprintf("pipe unix process output error: %s", err))
logger.ErrorContext(cmd.ctx, fmt.Sprintf("pipe unix process output error: %s", err))
}
break
}
if len(line) != 0 {
logger.Debug(string(line))
logger.DebugContext(cmd.ctx, string(line))
}
}
}
go logCommandOutput(cmd.logger.Named("stdout"), stdout)
go logCommandOutput(cmd.logger.Named("stderr"), stderr)
go logCommandOutput(cmd.logger.With(slog.String("logger", "stdout")), stdout)
go logCommandOutput(cmd.logger.With(slog.String("logger", "stderr")), stderr)
return nil
}
@@ -196,13 +194,13 @@ func (cmd *Cmd) Kill() error {
err := syscall.Kill(-cmd.process.Process.Pid, syscall.SIGKILL)
if err == nil {
cmd.logger.Debug("unix process killed")
cmd.logger.DebugContext(cmd.ctx, "unix process killed")
return nil
}
// If the process does not exist anymore, the error is irrelevant.
if strings.Contains(err.Error(), "no such process") {
cmd.logger.Debug("unix process already killed")
cmd.logger.DebugContext(cmd.ctx, "unix process already killed")
return nil
}

View File

@@ -10,7 +10,7 @@ import (
type Context struct {
flags ParsedFlags
descriptors []ModuleDescriptor
moduleInstances map[string]interface{}
moduleInstances map[string]any
}
// NewContext creates a [Context].
@@ -22,7 +22,7 @@ func NewContext(
return &Context{
flags: flags,
descriptors: descriptors,
moduleInstances: make(map[string]interface{}),
moduleInstances: make(map[string]any),
}
}
@@ -45,7 +45,7 @@ func (ctx *Context) ParsedFlags() ParsedFlags {
//
// If the module has not yet been initialized, this method
// initializes it. Otherwise, returns the already initialized instance.
func (ctx *Context) Module(kind interface{}) (interface{}, error) {
func (ctx *Context) Module(kind any) (any, error) {
mods, err := ctx.Modules(kind)
if err != nil {
return nil, fmt.Errorf("get module: %w", err)
@@ -70,10 +70,10 @@ func (ctx *Context) Module(kind interface{}) (interface{}, error) {
//
// If one or more modules have not yet been initialized, this method
// initializes them. Otherwise, returns the already initialized instances.
func (ctx *Context) Modules(kind interface{}) ([]interface{}, error) {
func (ctx *Context) Modules(kind any) ([]any, error) {
realKind := reflect.TypeOf(kind).Elem()
var mods []interface{}
var mods []any
for _, desc := range ctx.descriptors {
newInstance := desc.New()
@@ -101,7 +101,7 @@ func (ctx *Context) Modules(kind interface{}) ([]interface{}, error) {
// loadModule calls the Provision and/or Validate methods of the requested
// module if it satisfies the [Provisioner] and/or [Validator] interfaces.
func (ctx *Context) loadModule(id string, instance interface{}) error {
func (ctx *Context) loadModule(id string, instance any) error {
if prov, ok := instance.(Provisioner); ok {
// The instance can be provisioned.
err := prov.Provision(ctx)

View File

@@ -9,7 +9,7 @@ func TestContext_Module(t *testing.T) {
for _, tc := range []struct {
scenario string
mods []ModuleDescriptor
kind interface{}
kind any
expectError bool
}{
{
@@ -80,7 +80,7 @@ func TestContext_Modules(t *testing.T) {
for _, tc := range []struct {
scenario string
mods []ModuleDescriptor
kind interface{}
kind any
expectError bool
}{
{
@@ -151,12 +151,12 @@ func TestContext_Modules(t *testing.T) {
func TestContext_loadModule(t *testing.T) {
for _, tc := range []struct {
scenario string
instance interface{}
instance any
expectError bool
}{
{
scenario: "module with error on provision",
instance: func() interface{} {
instance: func() any {
mod := &struct {
ModuleMock
ProvisionerMock
@@ -171,7 +171,7 @@ func TestContext_loadModule(t *testing.T) {
},
{
scenario: "module with error on validation",
instance: func() interface{} {
instance: func() any {
mod := &struct {
ModuleMock
ValidatorMock
@@ -186,7 +186,7 @@ func TestContext_loadModule(t *testing.T) {
},
{
scenario: "success",
instance: func() interface{} {
instance: func() any {
mod := &struct {
ModuleMock
ValidatorMock

View File

@@ -4,17 +4,19 @@ import (
"runtime"
"sort"
"sync"
"time"
flag "github.com/spf13/pflag"
)
// DebugInfo gathers data for debugging.
type DebugInfo struct {
Version string `json:"version"`
Architecture string `json:"architecture"`
Modules []string `json:"modules"`
ModulesAdditionalData map[string]map[string]interface{} `json:"modules_additional_data"`
Flags map[string]interface{} `json:"flags"`
Version string `json:"version"`
Timezone string `json:"timezone"`
Architecture string `json:"architecture"`
Modules []string `json:"modules"`
ModulesAdditionalData map[string]map[string]any `json:"modules_additional_data"`
Flags map[string]any `json:"flags"`
}
// BuildDebug builds the debug data from modules.
@@ -24,10 +26,11 @@ func BuildDebug(ctx *Context) {
debug = &DebugInfo{
Version: Version,
Timezone: time.Now().Location().String(),
Architecture: runtime.GOARCH,
Modules: make([]string, len(ctx.moduleInstances)),
ModulesAdditionalData: make(map[string]map[string]interface{}),
Flags: make(map[string]interface{}),
ModulesAdditionalData: make(map[string]map[string]any),
Flags: make(map[string]any),
}
i := 0

View File

@@ -13,6 +13,8 @@ func TestBuildDebug(t *testing.T) {
t.Errorf("Debug() should return empty debug data")
}
t.Setenv("TZ", "UTC")
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
fs.String("foo", "bar", "Set foo")
ctx := NewContext(ParsedFlags{
@@ -31,8 +33,8 @@ func TestBuildDebug(t *testing.T) {
mod2.DescriptorMock = func() ModuleDescriptor {
return ModuleDescriptor{ID: "bar", New: func() Module { return mod2 }}
}
mod2.DebugMock = func() map[string]interface{} {
return map[string]interface{}{
mod2.DebugMock = func() map[string]any {
return map[string]any{
"foo": "bar",
}
}
@@ -51,17 +53,18 @@ func TestBuildDebug(t *testing.T) {
expect := DebugInfo{
Version: Version,
Timezone: "UTC",
Architecture: runtime.GOARCH,
Modules: []string{
"bar",
"foo",
},
ModulesAdditionalData: map[string]map[string]interface{}{
ModulesAdditionalData: map[string]map[string]any{
"bar": {
"foo": "bar",
},
},
Flags: map[string]interface{}{
Flags: map[string]any{
"foo": "bar",
},
}

View File

@@ -1,19 +1,19 @@
package gotenberg
import (
"context"
"fmt"
"log/slog"
"os"
"path/filepath"
"strings"
"time"
"go.uber.org/zap"
)
// GarbageCollect scans the root path and deletes files or directories with
// names containing specific substrings and before a given expiration time.
func GarbageCollect(logger *zap.Logger, rootPath string, includeSubstr []string, expirationTime time.Time) error {
logger = logger.Named("gc")
func GarbageCollect(ctx context.Context, logger *slog.Logger, rootPath string, includeSubstr []string, expirationTime time.Time) error {
logger = logger.With(slog.String("logger", "gc"))
// To make sure that the next Walk method stays on
// the root level of the considered path, we have to
@@ -43,7 +43,7 @@ func GarbageCollect(logger *zap.Logger, rootPath string, includeSubstr []string,
return fmt.Errorf("garbage collect '%s': %w", path, err)
}
logger.Debug(fmt.Sprintf("'%s' removed", path))
logger.DebugContext(ctx, fmt.Sprintf("'%s' removed", path))
return skipDirOrNil(info)
}

View File

@@ -1,14 +1,15 @@
package gotenberg
import (
"context"
"fmt"
"log/slog"
"os"
"path"
"testing"
"time"
"github.com/google/uuid"
"go.uber.org/zap"
)
func TestGarbageCollect(t *testing.T) {
@@ -66,7 +67,7 @@ func TestGarbageCollect(t *testing.T) {
}
}()
err := GarbageCollect(zap.NewNop(), tc.rootPath, tc.includeSubstr, time.Now())
err := GarbageCollect(context.Background(), slog.New(slog.NewJSONHandler(os.Stdout, nil)), tc.rootPath, tc.includeSubstr, time.Now())
if !tc.expectError && err != nil {
t.Fatalf("expected no error but got: %v", err)

View File

@@ -1,9 +1,8 @@
package logging
package log
import (
"fmt"
"go.uber.org/zap/zapcore"
"log/slog"
)
// Foreground colors.
@@ -25,23 +24,15 @@ func (c color) Add(s string) string {
return fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(c), s)
}
func levelToColor(l zapcore.Level) color {
func levelToColor(l slog.Level) color {
switch l {
case zapcore.DebugLevel:
case slog.LevelDebug:
return cyan
case zapcore.InfoLevel:
case slog.LevelInfo:
return blue
case zapcore.WarnLevel:
case slog.LevelWarn:
return yellow
case zapcore.ErrorLevel:
return red
case zapcore.DPanicLevel:
return red
case zapcore.PanicLevel:
return red
case zapcore.FatalLevel:
return red
case zapcore.InvalidLevel:
case slog.LevelError:
return red
default:
return red

View File

@@ -0,0 +1,2 @@
// Package log gathers internal logging utilities.
package log

View File

@@ -0,0 +1,18 @@
package log
import "log/slog"
func gcpSeverity(l slog.Level) string {
switch {
case l < slog.LevelInfo:
return "DEBUG"
case l < slog.LevelWarn:
return "INFO"
case l < slog.LevelError:
return "WARNING"
case l >= slog.LevelError:
return "ERROR"
default:
return "DEFAULT"
}
}

View File

@@ -0,0 +1,171 @@
package log
import (
"context"
"errors"
"log/slog"
)
type gotenbergHandler struct {
slog.Handler
fieldsPrefix string
loggerName string
}
func NewGotenbergHandler(next slog.Handler, prefix string) slog.Handler {
return &gotenbergHandler{Handler: next, fieldsPrefix: prefix}
}
func (h *gotenbergHandler) Handle(ctx context.Context, r slog.Record) error {
var newAttrs []slog.Attr
if h.loggerName != "" {
newAttrs = append(newAttrs, slog.String("logger", h.loggerName))
}
var needsNewRecord bool
if len(newAttrs) > 0 {
needsNewRecord = true
}
if h.fieldsPrefix != "" {
r.Attrs(func(a slog.Attr) bool {
if a.Key == "logger" || a.Key == "correlation_id" || a.Key == "trace_id" || a.Key == "span_id" {
newAttrs = append(newAttrs, a)
needsNewRecord = true
return true
}
a.Key = h.fieldsPrefix + "_" + a.Key
newAttrs = append(newAttrs, a)
needsNewRecord = true
return true
})
} else if needsNewRecord {
r.Attrs(func(a slog.Attr) bool {
newAttrs = append(newAttrs, a)
return true
})
}
if needsNewRecord {
newR := slog.NewRecord(r.Time, r.Level, r.Message, r.PC)
newR.AddAttrs(newAttrs...)
r = newR
}
return h.Handler.Handle(ctx, r)
}
func (h *gotenbergHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
var prefixed []slog.Attr
newLoggerName := h.loggerName
for _, a := range attrs {
if a.Key == "logger" {
if newLoggerName == "" {
newLoggerName = a.Value.String()
} else {
newLoggerName = newLoggerName + "." + a.Value.String()
}
continue
}
if h.fieldsPrefix != "" {
if a.Key == "correlation_id" || a.Key == "trace_id" || a.Key == "span_id" {
// Don't prefix these keys
} else {
a.Key = h.fieldsPrefix + "_" + a.Key
}
}
prefixed = append(prefixed, a)
}
newHandler := h.Handler
if len(prefixed) > 0 {
newHandler = h.Handler.WithAttrs(prefixed)
}
return &gotenbergHandler{
Handler: newHandler,
fieldsPrefix: h.fieldsPrefix,
loggerName: newLoggerName,
}
}
func (h *gotenbergHandler) WithGroup(name string) slog.Handler {
return &gotenbergHandler{
Handler: h.Handler.WithGroup(name),
fieldsPrefix: h.fieldsPrefix,
loggerName: h.loggerName,
}
}
type multiHandler struct {
handlers []slog.Handler
}
func FanOut(handlers ...slog.Handler) slog.Handler {
return &multiHandler{handlers: handlers}
}
func (m *multiHandler) Enabled(ctx context.Context, level slog.Level) bool {
for _, h := range m.handlers {
if h.Enabled(ctx, level) {
return true
}
}
return false
}
func (m *multiHandler) Handle(ctx context.Context, r slog.Record) error {
var errs []error
for _, h := range m.handlers {
if h.Enabled(ctx, r.Level) {
if err := h.Handle(ctx, r.Clone()); err != nil {
errs = append(errs, err)
}
}
}
return errors.Join(errs...)
}
func (m *multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
cloned := make([]slog.Handler, len(m.handlers))
for i, h := range m.handlers {
cloned[i] = h.WithAttrs(attrs)
}
return &multiHandler{handlers: cloned}
}
func (m *multiHandler) WithGroup(name string) slog.Handler {
cloned := make([]slog.Handler, len(m.handlers))
for i, h := range m.handlers {
cloned[i] = h.WithGroup(name)
}
return &multiHandler{handlers: cloned}
}
type levelHandler struct {
slog.Handler
level slog.Level
}
func LevelFilter(next slog.Handler, level slog.Level) slog.Handler {
return &levelHandler{Handler: next, level: level}
}
func (h *levelHandler) Enabled(ctx context.Context, level slog.Level) bool {
return level >= h.level && h.Handler.Enabled(ctx, level)
}
func (h *levelHandler) Handle(ctx context.Context, r slog.Record) error {
return h.Handler.Handle(ctx, r)
}
func (h *levelHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &levelHandler{Handler: h.Handler.WithAttrs(attrs), level: h.level}
}
func (h *levelHandler) WithGroup(name string) slog.Handler {
return &levelHandler{Handler: h.Handler.WithGroup(name), level: h.level}
}

View File

@@ -0,0 +1,37 @@
package log
import (
"log/slog"
"sync"
)
// InitLogger initializes the global logger.
func InitLogger(handler slog.Handler) {
if logger != nil {
return
}
mu.Lock()
defer mu.Unlock()
// Double check: ensure it wasn't initialized while we waited for the lock.
if logger != nil {
return
}
logger = slog.New(handler)
}
// Logger returns the global logger.
func Logger() *slog.Logger {
mu.Lock()
defer mu.Unlock()
return logger
}
// logger is Singleton so that we instantiate our [slog.Logger] only once.
var (
logger *slog.Logger
mu sync.Mutex
)

View File

@@ -0,0 +1,127 @@
package log
import (
"context"
"log/slog"
"os"
"strings"
"go.opentelemetry.io/otel/trace"
"golang.org/x/term"
)
const (
autoLoggingFormat = "auto"
jsonLoggingFormat = "json"
textLoggingFormat = "text"
)
// traceContextHandler is an internal wrapper that specifically injects
// trace_id and span_id into the log record before they are written to the standard output.
type traceContextHandler struct {
slog.Handler
}
func (h traceContextHandler) Handle(ctx context.Context, r slog.Record) error {
if spanCtx := trace.SpanContextFromContext(ctx); spanCtx.IsValid() {
// Since slog.Record is immutable with regards to adding attributes in-place,
// we must clone and add them.
newR := slog.NewRecord(r.Time, r.Level, r.Message, r.PC)
r.Attrs(func(a slog.Attr) bool {
newR.AddAttrs(a)
return true
})
newR.AddAttrs(
slog.String("trace_id", spanCtx.TraceID().String()),
slog.String("span_id", spanCtx.SpanID().String()),
)
r = newR
}
return h.Handler.Handle(ctx, r)
}
func (h traceContextHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return traceContextHandler{Handler: h.Handler.WithAttrs(attrs)}
}
func (h traceContextHandler) WithGroup(name string) slog.Handler {
return traceContextHandler{Handler: h.Handler.WithGroup(name)}
}
// NewStdHandler returns a [slog.Handler] instance for the standard output.
func NewStdHandler(level slog.Level, format string, fieldsPrefix string, enableGcpFields bool) (slog.Handler, error) {
// #nosec: G115
isTerminal := term.IsTerminal(int(os.Stdout.Fd()))
// Normalize the log format based on the output device.
if format == autoLoggingFormat {
if isTerminal {
format = textLoggingFormat
} else {
format = jsonLoggingFormat
}
}
opts := &slog.HandlerOptions{
Level: level,
}
opts.ReplaceAttr = func(groups []string, a slog.Attr) slog.Attr {
// Configure level encoding based on format and GCP settings.
if a.Key == slog.LevelKey {
l := a.Value.Any().(slog.Level)
if format == textLoggingFormat && isTerminal {
if enableGcpFields {
a.Value = slog.StringValue(gcpSeverityColorEncoder(l))
} else {
a.Value = slog.StringValue(levelToColor(l).Add(l.String()))
}
} else if enableGcpFields && format != textLoggingFormat {
a.Key = "severity"
a.Value = slog.StringValue(gcpSeverity(l))
} else {
a.Value = slog.StringValue(strings.ToLower(l.String()))
}
}
if a.Key == slog.TimeKey {
if enableGcpFields && format != textLoggingFormat {
a.Key = "time"
} else {
a.Key = "ts"
}
if isTerminal {
a.Value = slog.StringValue(a.Value.Time().Local().Format("2006/01/02 15:04:05.000"))
} else if !enableGcpFields {
a.Value = slog.Float64Value(float64(a.Value.Time().UnixNano()) / 1e9)
}
}
if a.Key == slog.MessageKey {
if enableGcpFields && format != textLoggingFormat {
a.Key = "message"
} else {
a.Key = "msg"
}
}
return a
}
var handler slog.Handler
if format == textLoggingFormat {
handler = slog.NewTextHandler(os.Stderr, opts)
} else {
handler = slog.NewJSONHandler(os.Stderr, opts)
}
return traceContextHandler{Handler: handler}, nil
}
func gcpSeverityColorEncoder(l slog.Level) string {
severity := gcpSeverity(l)
c := levelToColor(l)
return c.Add(severity)
}

View File

@@ -0,0 +1,8 @@
// Package otel gathers initialization utilities for OpenTelemetry
// instrumentation.
//
// This package has been significantly inspired by
// https://github.com/lucavallin/gotel.
//
// See: https://opentelemetry.io/.
package otel

View File

@@ -0,0 +1,166 @@
package otel
import (
"context"
"fmt"
"log/slog"
"os"
"sync/atomic"
"go.opentelemetry.io/contrib/bridges/otelslog"
"go.opentelemetry.io/contrib/exporters/autoexport"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.40.0"
)
// InitTracerProvider initializes the OpenTelemetry tracer provider.
func InitTracerProvider(logger *slog.Logger, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) {
initOtelLogger(logger)
ctx := context.Background()
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("get hostname: %w", err)
}
res, err := resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(serviceName),
semconv.ServiceVersion(serviceVersion),
semconv.HostName(hostname),
),
)
if err != nil {
return nil, fmt.Errorf("merge resource: %w", err)
}
traceOpts := []trace.TracerProviderOption{
trace.WithResource(res),
}
traceExporter, err := autoexport.NewSpanExporter(ctx)
if err != nil {
return nil, err
}
if !autoexport.IsNoneSpanExporter(traceExporter) {
traceOpts = append(traceOpts, trace.WithBatcher(traceExporter))
}
traceProvider := trace.NewTracerProvider(traceOpts...)
otel.SetTracerProvider(traceProvider)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
))
return traceProvider.Shutdown, nil
}
// InitMeterProvider initializes the OpenTelemetry meter provider.
func InitMeterProvider(logger *slog.Logger, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) {
initOtelLogger(logger)
ctx := context.Background()
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("get hostname: %w", err)
}
res, err := resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(serviceName),
semconv.ServiceVersion(serviceVersion),
semconv.HostName(hostname),
),
)
if err != nil {
return nil, fmt.Errorf("merge resource: %w", err)
}
metricOpts := []metric.Option{
metric.WithResource(res),
}
metricReader, err := autoexport.NewMetricReader(ctx)
if err != nil {
return nil, err
}
if !autoexport.IsNoneMetricReader(metricReader) {
metricOpts = append(metricOpts, metric.WithReader(metricReader))
}
meterProvider := metric.NewMeterProvider(metricOpts...)
otel.SetMeterProvider(meterProvider)
return meterProvider.Shutdown, nil
}
// InitLoggerProvider initializes the OpenTelemetry logger provider.
func InitLoggerProvider(logger *slog.Logger, serviceName, serviceVersion string) (shutdown func(context.Context) error, handler slog.Handler, err error) {
initOtelLogger(logger)
ctx := context.Background()
hostname, err := os.Hostname()
if err != nil {
return nil, nil, fmt.Errorf("get hostname: %w", err)
}
res, err := resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(serviceName),
semconv.ServiceVersion(serviceVersion),
semconv.HostName(hostname),
),
)
if err != nil {
return nil, nil, fmt.Errorf("merge resource: %w", err)
}
logOpts := []log.LoggerProviderOption{
log.WithResource(res),
}
logExporter, err := autoexport.NewLogExporter(ctx)
if err != nil {
return nil, nil, err
}
if !autoexport.IsNoneLogExporter(logExporter) {
logOpts = append(logOpts, log.WithProcessor(log.NewBatchProcessor(logExporter)))
}
loggerProvider := log.NewLoggerProvider(logOpts...)
otelHandler := otelslog.NewHandler(serviceName, otelslog.WithLoggerProvider(loggerProvider))
global.SetLoggerProvider(loggerProvider)
return loggerProvider.Shutdown, otelHandler, nil
}
func initOtelLogger(logger *slog.Logger) {
if otlpLoggerInitialized.Load() {
return
}
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
logger.Error(err.Error())
}))
otlpLoggerInitialized.Store(true)
}
var otlpLoggerInitialized atomic.Bool

View File

@@ -1,57 +0,0 @@
package gotenberg
import (
"fmt"
"github.com/hashicorp/go-retryablehttp"
"go.uber.org/zap"
)
// LoggerProvider is an interface for a module that supplies a method for
// creating a [zap.Logger] instance for use by other modules.
//
// func (m *YourModule) Provision(ctx *gotenberg.Context) error {
// provider, _ := ctx.Module(new(gotenberg.LoggerProvider))
// logger, _ := provider.(gotenberg.LoggerProvider).Logger(m)
// }
type LoggerProvider interface {
Logger(mod Module) (*zap.Logger, error)
}
// LeveledLogger is a wrapper around a [zap.Logger] so that it may be used by a
// [retryablehttp.Client].
type LeveledLogger struct {
logger *zap.Logger
}
// NewLeveledLogger instantiates a [LeveledLogger].
func NewLeveledLogger(logger *zap.Logger) *LeveledLogger {
return &LeveledLogger{
logger: logger,
}
}
// Error logs a message at the error level using the wrapped zap.Logger.
func (leveled LeveledLogger) Error(msg string, keysAndValues ...interface{}) {
leveled.logger.Error(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}
// Warn logs a message at the warning level using the wrapped zap.Logger.
func (leveled LeveledLogger) Warn(msg string, keysAndValues ...interface{}) {
leveled.logger.Warn(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}
// Info logs a message at the info level using the wrapped zap.Logger.
func (leveled LeveledLogger) Info(msg string, keysAndValues ...interface{}) {
leveled.logger.Info(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}
// Debug logs a message at the debug level using the wrapped zap.Logger.
func (leveled LeveledLogger) Debug(msg string, keysAndValues ...interface{}) {
leveled.logger.Debug(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}
// Interface guards.
var (
_ retryablehttp.LeveledLogger = (*LeveledLogger)(nil)
)

View File

@@ -1,26 +0,0 @@
package gotenberg
// Metric represents a unitary metric.
type Metric struct {
// Name is the unique identifier.
// Required.
Name string
// Description describes the metric.
// Optional.
Description string
// Read returns the current value.
// Required.
Read func() float64
}
// MetricsProvider is a module interface which provides a list of [Metric].
//
// func (m *YourModule) Provision(ctx *gotenberg.Context) error {
// provider, _ := ctx.Module(new(gotenberg.MetricsProvider))
// metrics, _ := provider.(gotenberg.MetricsProvider).Metrics()
// }
type MetricsProvider interface {
Metrics() ([]Metric, error)
}

View File

@@ -2,9 +2,8 @@ package gotenberg
import (
"context"
"log/slog"
"os"
"go.uber.org/zap"
)
// ModuleMock is a mock for the [Module] interface.
@@ -35,10 +34,10 @@ func (mod *ValidatorMock) Validate() error {
}
type DebuggableMock struct {
DebugMock func() map[string]interface{}
DebugMock func() map[string]any
}
func (mod *DebuggableMock) Debug() map[string]interface{} {
func (mod *DebuggableMock) Debug() map[string]any {
return mod.DebugMock()
}
@@ -46,38 +45,48 @@ func (mod *DebuggableMock) Debug() map[string]interface{} {
//
//nolint:dupl
type PdfEngineMock struct {
MergeMock func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error
SplitMock func(ctx context.Context, logger *zap.Logger, mode SplitMode, inputPath, outputDirPath string) ([]string, error)
FlattenMock func(ctx context.Context, logger *zap.Logger, inputPath string) error
ConvertMock func(ctx context.Context, logger *zap.Logger, formats PdfFormats, inputPath, outputPath string) error
ReadMetadataMock func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error)
WriteMetadataMock func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error
MergeMock func(ctx context.Context, logger *slog.Logger, inputPaths []string, outputPath string) error
SplitMock func(ctx context.Context, logger *slog.Logger, mode SplitMode, inputPath, outputDirPath string) ([]string, error)
FlattenMock func(ctx context.Context, logger *slog.Logger, inputPath string) error
ConvertMock func(ctx context.Context, logger *slog.Logger, formats PdfFormats, inputPath, outputPath string) error
ReadMetadataMock func(ctx context.Context, logger *slog.Logger, inputPath string) (map[string]any, error)
WriteMetadataMock func(ctx context.Context, logger *slog.Logger, metadata map[string]any, inputPath string) error
EncryptMock func(ctx context.Context, logger *slog.Logger, inputPath, userPassword, ownerPassword string) error
AddAttachmentsMock func(ctx context.Context, logger *slog.Logger, filePaths []string, inputPath string) error
}
func (engine *PdfEngineMock) Merge(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
func (engine *PdfEngineMock) Merge(ctx context.Context, logger *slog.Logger, inputPaths []string, outputPath string) error {
return engine.MergeMock(ctx, logger, inputPaths, outputPath)
}
func (engine *PdfEngineMock) Split(ctx context.Context, logger *zap.Logger, mode SplitMode, inputPath, outputDirPath string) ([]string, error) {
func (engine *PdfEngineMock) Split(ctx context.Context, logger *slog.Logger, mode SplitMode, inputPath, outputDirPath string) ([]string, error) {
return engine.SplitMock(ctx, logger, mode, inputPath, outputDirPath)
}
func (engine *PdfEngineMock) Flatten(ctx context.Context, logger *zap.Logger, inputPath string) error {
func (engine *PdfEngineMock) Flatten(ctx context.Context, logger *slog.Logger, inputPath string) error {
return engine.FlattenMock(ctx, logger, inputPath)
}
func (engine *PdfEngineMock) Convert(ctx context.Context, logger *zap.Logger, formats PdfFormats, inputPath, outputPath string) error {
func (engine *PdfEngineMock) Convert(ctx context.Context, logger *slog.Logger, formats PdfFormats, inputPath, outputPath string) error {
return engine.ConvertMock(ctx, logger, formats, inputPath, outputPath)
}
func (engine *PdfEngineMock) ReadMetadata(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
func (engine *PdfEngineMock) ReadMetadata(ctx context.Context, logger *slog.Logger, inputPath string) (map[string]any, error) {
return engine.ReadMetadataMock(ctx, logger, inputPath)
}
func (engine *PdfEngineMock) WriteMetadata(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
func (engine *PdfEngineMock) WriteMetadata(ctx context.Context, logger *slog.Logger, metadata map[string]any, inputPath string) error {
return engine.WriteMetadataMock(ctx, logger, metadata, inputPath)
}
func (engine *PdfEngineMock) Encrypt(ctx context.Context, logger *slog.Logger, inputPath, userPassword, ownerPassword string) error {
return engine.EncryptMock(ctx, logger, inputPath, userPassword, ownerPassword)
}
func (engine *PdfEngineMock) AddAttachments(ctx context.Context, logger *slog.Logger, filePaths []string, inputPath string) error {
return engine.AddAttachmentsMock(ctx, logger, filePaths, inputPath)
}
// PdfEngineProviderMock is a mock for the [PdfEngineProvider] interface.
type PdfEngineProviderMock struct {
PdfEngineMock func() (PdfEngine, error)
@@ -89,31 +98,32 @@ func (provider *PdfEngineProviderMock) PdfEngine() (PdfEngine, error) {
// ProcessMock is a mock for the [Process] interface.
type ProcessMock struct {
StartMock func(logger *zap.Logger) error
StopMock func(logger *zap.Logger) error
HealthyMock func(logger *zap.Logger) bool
StartMock func(logger *slog.Logger) error
StopMock func(logger *slog.Logger) error
HealthyMock func(logger *slog.Logger) bool
}
func (p *ProcessMock) Start(logger *zap.Logger) error {
func (p *ProcessMock) Start(logger *slog.Logger) error {
return p.StartMock(logger)
}
func (p *ProcessMock) Stop(logger *zap.Logger) error {
func (p *ProcessMock) Stop(logger *slog.Logger) error {
return p.StopMock(logger)
}
func (p *ProcessMock) Healthy(logger *zap.Logger) bool {
func (p *ProcessMock) Healthy(logger *slog.Logger) bool {
return p.HealthyMock(logger)
}
// ProcessSupervisorMock is a mock for the [ProcessSupervisor] interface.
type ProcessSupervisorMock struct {
LaunchMock func() error
ShutdownMock func() error
HealthyMock func() bool
RunMock func(ctx context.Context, logger *zap.Logger, task func() error) error
ReqQueueSizeMock func() int64
RestartsCountMock func() int64
LaunchMock func() error
ShutdownMock func() error
HealthyMock func() bool
RunMock func(ctx context.Context, logger *slog.Logger, task func() error) error
ReqQueueSizeMock func() int64
ActiveTasksCountMock func() int64
RestartsCountMock func() int64
}
func (s *ProcessSupervisorMock) Launch() error {
@@ -128,7 +138,7 @@ func (s *ProcessSupervisorMock) Healthy() bool {
return s.HealthyMock()
}
func (s *ProcessSupervisorMock) Run(ctx context.Context, logger *zap.Logger, task func() error) error {
func (s *ProcessSupervisorMock) Run(ctx context.Context, logger *slog.Logger, task func() error) error {
return s.RunMock(ctx, logger, task)
}
@@ -136,28 +146,14 @@ func (s *ProcessSupervisorMock) ReqQueueSize() int64 {
return s.ReqQueueSizeMock()
}
func (s *ProcessSupervisorMock) ActiveTasksCount() int64 {
return s.ActiveTasksCountMock()
}
func (s *ProcessSupervisorMock) RestartsCount() int64 {
return s.RestartsCountMock()
}
// LoggerProviderMock is a mock for the [LoggerProvider] interface.
type LoggerProviderMock struct {
LoggerMock func(mod Module) (*zap.Logger, error)
}
func (provider *LoggerProviderMock) Logger(mod Module) (*zap.Logger, error) {
return provider.LoggerMock(mod)
}
// MetricsProviderMock is a mock for the [MetricsProvider] interface.
type MetricsProviderMock struct {
MetricsMock func() ([]Metric, error)
}
func (provider *MetricsProviderMock) Metrics() ([]Metric, error) {
return provider.MetricsMock()
}
// MkdirAllMock is a mock for the [MkdirAll] interface.
type MkdirAllMock struct {
MkdirAllMock func(path string, perm os.FileMode) error
@@ -184,8 +180,6 @@ var (
_ PdfEngineProvider = (*PdfEngineProviderMock)(nil)
_ Process = (*ProcessMock)(nil)
_ ProcessSupervisor = (*ProcessSupervisorMock)(nil)
_ LoggerProvider = (*LoggerProviderMock)(nil)
_ MetricsProvider = (*MetricsProviderMock)(nil)
_ MkdirAll = (*MkdirAllMock)(nil)
_ PathRename = (*PathRenameMock)(nil)
)

View File

@@ -78,7 +78,7 @@ type SystemLogger interface {
// Debuggable is a module interface for modules which want to provide
// additional debug data.
type Debuggable interface {
Debug() map[string]interface{}
Debug() map[string]any
}
// MustRegisterModule registers a module.

View File

@@ -3,8 +3,8 @@ package gotenberg
import (
"context"
"errors"
"go.uber.org/zap"
"fmt"
"log/slog"
)
var (
@@ -23,8 +23,31 @@ var (
// ErrPdfEngineMetadataValueNotSupported is returned when a metadata value
// is not supported.
ErrPdfEngineMetadataValueNotSupported = errors.New("metadata value not supported")
// ErrPdfEncryptionNotSupported is returned when encryption
// is not supported by the PDF engine.
ErrPdfEncryptionNotSupported = errors.New("encryption not supported")
)
// PdfEngineInvalidArgsError represents an error returned by a PDF engine when
// invalid arguments are provided. It includes the name of the engine and a
// detailed message describing the issue.
type PdfEngineInvalidArgsError struct {
engine string
msg string
}
// Error implements the error interface.
func (e *PdfEngineInvalidArgsError) Error() string {
return fmt.Sprintf("%s: %s", e.engine, e.msg)
}
// NewPdfEngineInvalidArgs creates a new PdfEngineInvalidArgsError with the
// given engine name and message.
func NewPdfEngineInvalidArgs(engine, msg string) error {
return &PdfEngineInvalidArgsError{engine, msg}
}
const (
// SplitModeIntervals represents a mode where a PDF is split at specific
// intervals.
@@ -93,26 +116,36 @@ type PdfFormats struct {
type PdfEngine interface {
// Merge combines multiple PDFs into a single PDF. The resulting page order
// is determined by the order of files provided in inputPaths.
Merge(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error
Merge(ctx context.Context, logger *slog.Logger, inputPaths []string, outputPath string) error
// Split splits a given PDF file.
Split(ctx context.Context, logger *zap.Logger, mode SplitMode, inputPath, outputDirPath string) ([]string, error)
Split(ctx context.Context, logger *slog.Logger, mode SplitMode, inputPath, outputDirPath string) ([]string, error)
// Flatten merges existing annotation appearances with page content,
// effectively deleting the original annotations. This process can flatten
// forms as well, as forms share a relationship with annotations. Note that
// forms as well as forms share a relationship with annotations. Note that
// this operation is irreversible.
Flatten(ctx context.Context, logger *zap.Logger, inputPath string) error
Flatten(ctx context.Context, logger *slog.Logger, inputPath string) error
// Convert transforms a given PDF to the specified formats defined in
// PdfFormats. If no format, it does nothing.
Convert(ctx context.Context, logger *zap.Logger, formats PdfFormats, inputPath, outputPath string) error
Convert(ctx context.Context, logger *slog.Logger, formats PdfFormats, inputPath, outputPath string) error
// ReadMetadata extracts the metadata of a given PDF file.
ReadMetadata(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error)
ReadMetadata(ctx context.Context, logger *slog.Logger, inputPath string) (map[string]any, error)
// WriteMetadata writes the metadata into a given PDF file.
WriteMetadata(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error
WriteMetadata(ctx context.Context, logger *slog.Logger, metadata map[string]any, inputPath string) error
// Encrypt adds password protection to a PDF file.
// The userPassword is required to open the document.
// The ownerPassword provides full access to the document.
// If the ownerPassword is empty, it defaults to the userPassword.
Encrypt(ctx context.Context, logger *slog.Logger, inputPath, userPassword, ownerPassword string) error
// AddAttachments adds attachments into a PDF. All files are attached as
// file attachments without modifying the main PDF content.
AddAttachments(ctx context.Context, logger *slog.Logger, filePaths []string, inputPath string) error
}
// PdfEngineProvider offers an interface to instantiate a [PdfEngine].

View File

@@ -0,0 +1,48 @@
// Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconv/bench_test.go.tmpl
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv
import (
"net/http"
"net/url"
"testing"
"go.opentelemetry.io/otel/attribute"
)
var benchHTTPServerRequestResults []attribute.KeyValue
// BenchmarkHTTPServerRequest allows comparison between different version of the HTTP server.
// To use an alternative start this test with OTEL_SEMCONV_STABILITY_OPT_IN set to the
// version under test.
func BenchmarkHTTPServerRequest(b *testing.B) {
// Request was generated from TestHTTPServerRequest request.
req := &http.Request{
Method: http.MethodGet,
URL: &url.URL{
Path: "/",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: http.Header{
"User-Agent": []string{"Go-http-client/1.1"},
"Accept-Encoding": []string{"gzip"},
},
Body: http.NoBody,
Host: "127.0.0.1:39093",
RemoteAddr: "127.0.0.1:38738",
RequestURI: "/",
}
serv := NewHTTPServer(nil)
b.ReportAllocs()
b.ResetTimer()
for range b.N {
benchHTTPServerRequestResults = serv.RequestTraceAttrs("", req, RequestTraceAttrsOpts{})
}
}

View File

@@ -0,0 +1,308 @@
// Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconv/client.go.tmpl
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package semconv provides OpenTelemetry semantic convention types and
// functionality.
package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
import (
"context"
"fmt"
"net/http"
"reflect"
"slices"
"strconv"
"strings"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/semconv/v1.39.0"
"go.opentelemetry.io/otel/semconv/v1.39.0/httpconv"
)
type HTTPClient struct {
requestBodySize httpconv.ClientRequestBodySize
requestDuration httpconv.ClientRequestDuration
}
func NewHTTPClient(meter metric.Meter) HTTPClient {
client := HTTPClient{}
var err error
client.requestBodySize, err = httpconv.NewClientRequestBodySize(meter)
handleErr(err)
client.requestDuration, err = httpconv.NewClientRequestDuration(
meter,
metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10),
)
handleErr(err)
return client
}
func (n HTTPClient) Status(code int) (codes.Code, string) {
if code == 0 {
return codes.Error, "No HTTP status code"
}
if code < 100 || code >= 600 {
return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code)
}
if code >= 400 {
return codes.Error, http.StatusText(code)
}
return codes.Ok, ""
}
// RequestTraceAttrs returns trace attributes for an HTTP request made by a client.
func (n HTTPClient) RequestTraceAttrs(req *http.Request) []attribute.KeyValue {
/*
below attributes are returned:
- http.request.method
- http.request.method.original
- url.full
- server.address
- server.port
- network.protocol.name
- network.protocol.version
*/
numOfAttributes := 3 // URL, server address, proto, and method.
var urlHost string
if req.URL != nil {
urlHost = req.URL.Host
}
var requestHost string
var requestPort int
for _, hostport := range []string{urlHost, req.Header.Get("Host")} {
requestHost, requestPort = SplitHostPort(hostport)
if requestHost != "" || requestPort > 0 {
break
}
}
eligiblePort := requiredHTTPPort(req.URL != nil && req.URL.Scheme == "https", requestPort)
if eligiblePort > 0 {
numOfAttributes++
}
useragent := req.UserAgent()
if useragent != "" {
numOfAttributes++
}
protoName, protoVersion := netProtocol(req.Proto)
if protoName != "" && protoName != "http" {
numOfAttributes++
}
if protoVersion != "" {
numOfAttributes++
}
method, originalMethod := n.method(req.Method)
if originalMethod != (attribute.KeyValue{}) {
numOfAttributes++
}
attrs := make([]attribute.KeyValue, 0, numOfAttributes)
attrs = append(attrs, method)
if originalMethod != (attribute.KeyValue{}) {
attrs = append(attrs, originalMethod)
}
var u string
if req.URL != nil {
// Remove any username/password info that may be in the URL.
userinfo := req.URL.User
req.URL.User = nil
u = req.URL.String()
// Restore any username/password info that was removed.
req.URL.User = userinfo
}
attrs = append(attrs, semconv.URLFull(u))
attrs = append(attrs, semconv.ServerAddress(requestHost))
if eligiblePort > 0 {
attrs = append(attrs, semconv.ServerPort(eligiblePort))
}
if protoName != "" && protoName != "http" {
attrs = append(attrs, semconv.NetworkProtocolName(protoName))
}
if protoVersion != "" {
attrs = append(attrs, semconv.NetworkProtocolVersion(protoVersion))
}
return attrs
}
// ResponseTraceAttrs returns trace attributes for an HTTP response made by a client.
func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue {
/*
below attributes are returned:
- http.response.status_code
- error.type
*/
var count int
if resp.StatusCode > 0 {
count++
}
if isErrorStatusCode(resp.StatusCode) {
count++
}
attrs := make([]attribute.KeyValue, 0, count)
if resp.StatusCode > 0 {
attrs = append(attrs, semconv.HTTPResponseStatusCode(resp.StatusCode))
}
if isErrorStatusCode(resp.StatusCode) {
errorType := strconv.Itoa(resp.StatusCode)
attrs = append(attrs, semconv.ErrorTypeKey.String(errorType))
}
return attrs
}
func (n HTTPClient) ErrorType(err error) attribute.KeyValue {
t := reflect.TypeOf(err)
var value string
if t.PkgPath() == "" && t.Name() == "" {
// Likely a builtin type.
value = t.String()
} else {
value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name())
}
if value == "" {
return semconv.ErrorTypeOther
}
return semconv.ErrorTypeKey.String(value)
}
func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) {
if method == "" {
return semconv.HTTPRequestMethodGet, attribute.KeyValue{}
}
if attr, ok := methodLookup[method]; ok {
return attr, attribute.KeyValue{}
}
orig := semconv.HTTPRequestMethodOriginal(method)
if attr, ok := methodLookup[strings.ToUpper(method)]; ok {
return attr, orig
}
return semconv.HTTPRequestMethodGet, orig
}
func (n HTTPClient) MetricAttributes(req *http.Request, statusCode int, additionalAttributes []attribute.KeyValue) []attribute.KeyValue {
num := len(additionalAttributes) + 2
var h string
if req.URL != nil {
h = req.URL.Host
}
var requestHost string
var requestPort int
for _, hostport := range []string{h, req.Header.Get("Host")} {
requestHost, requestPort = SplitHostPort(hostport)
if requestHost != "" || requestPort > 0 {
break
}
}
port := requiredHTTPPort(req.URL != nil && req.URL.Scheme == "https", requestPort)
if port > 0 {
num++
}
protoName, protoVersion := netProtocol(req.Proto)
if protoName != "" {
num++
}
if protoVersion != "" {
num++
}
if statusCode > 0 {
num++
}
attributes := slices.Grow(additionalAttributes, num)
attributes = append(attributes,
semconv.HTTPRequestMethodKey.String(standardizeHTTPMethod(req.Method)),
semconv.ServerAddress(requestHost),
n.scheme(req),
)
if port > 0 {
attributes = append(attributes, semconv.ServerPort(port))
}
if protoName != "" {
attributes = append(attributes, semconv.NetworkProtocolName(protoName))
}
if protoVersion != "" {
attributes = append(attributes, semconv.NetworkProtocolVersion(protoVersion))
}
if statusCode > 0 {
attributes = append(attributes, semconv.HTTPResponseStatusCode(statusCode))
}
return attributes
}
type MetricOpts struct {
measurement metric.MeasurementOption
addOptions metric.AddOption
}
func (o MetricOpts) MeasurementOption() metric.MeasurementOption {
return o.measurement
}
func (o MetricOpts) AddOptions() metric.AddOption {
return o.addOptions
}
func (n HTTPClient) MetricOptions(ma MetricAttributes) map[string]MetricOpts {
opts := map[string]MetricOpts{}
attributes := n.MetricAttributes(ma.Req, ma.StatusCode, ma.AdditionalAttributes)
set := metric.WithAttributeSet(attribute.NewSet(attributes...))
opts["new"] = MetricOpts{
measurement: set,
addOptions: set,
}
return opts
}
func (n HTTPClient) RecordMetrics(ctx context.Context, md MetricData, opts map[string]MetricOpts) {
n.requestBodySize.Inst().Record(ctx, md.RequestSize, opts["new"].MeasurementOption())
n.requestDuration.Inst().Record(ctx, md.ElapsedTime/1000, opts["new"].MeasurementOption())
}
// TraceAttributes returns attributes for httptrace.
func (n HTTPClient) TraceAttributes(host string) []attribute.KeyValue {
return []attribute.KeyValue{
semconv.ServerAddress(host),
}
}
func (n HTTPClient) scheme(req *http.Request) attribute.KeyValue {
if req.URL != nil && req.URL.Scheme != "" {
return semconv.URLScheme(req.URL.Scheme)
}
if req.TLS != nil {
return semconv.URLScheme("https")
}
return semconv.URLScheme("http")
}
func isErrorStatusCode(code int) bool {
return code >= 400 || code < 100
}

Some files were not shown because too many files have changed in this diff Show More