diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index aee84d562..5734f3a4b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -25,7 +25,7 @@ jobs: uses: ./.github/workflows/env - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 with: languages: go @@ -33,7 +33,7 @@ jobs: run: make - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 with: category: "/language:Go" timeout-minutes: 10 diff --git a/.github/workflows/collector-tests.yml b/.github/workflows/collector-tests.yml index c230c5b54..155a8991b 100644 --- a/.github/workflows/collector-tests.yml +++ b/.github/workflows/collector-tests.yml @@ -26,7 +26,7 @@ jobs: - name: Set up environment uses: ./.github/workflows/env - name: Set up Go Stable - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: stable - name: Cache coredump modules @@ -72,7 +72,7 @@ jobs: - name: Checkout Repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go Stable - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: stable - name: Clone Collector diff --git a/.github/workflows/env/action.yml b/.github/workflows/env/action.yml index 00fb0d615..cb412c456 100644 --- a/.github/workflows/env/action.yml +++ b/.github/workflows/env/action.yml @@ -23,7 +23,7 @@ runs: aarch64) command -v aarch64-linux-gnu-gcc >/dev/null || sudo apt-get install -y gcc-aarch64-linux-gnu ;; esac - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: go.mod cache-dependency-path: go.sum diff --git a/.github/workflows/fossa.yml b/.github/workflows/fossa.yml index ac5354c5d..5b73209af 100644 --- a/.github/workflows/fossa.yml +++ b/.github/workflows/fossa.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: fossas/fossa-action@c414b9ad82eaad041e47a7cf62a4f02411f427a0 # v1.8.0 + - uses: fossas/fossa-action@ff70fe9fe17cbd2040648f1c45e8ec4e4884dcf3 # v1.9.0 with: api-key: ${{secrets.FOSSA_API_KEY}} team: OpenTelemetry diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index b03b67ef4..8f3f3911c 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 with: sarif_file: results.sarif diff --git a/.github/workflows/push-docker-image.yml b/.github/workflows/push-docker-image.yml index b7d1c6708..9cf327fb4 100644 --- a/.github/workflows/push-docker-image.yml +++ b/.github/workflows/push-docker-image.yml @@ -18,7 +18,7 @@ jobs: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Login to Docker Hub - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/unit-test-on-pull-request.yml b/.github/workflows/unit-test-on-pull-request.yml index b167d2c3a..666ff0ce7 100644 --- a/.github/workflows/unit-test-on-pull-request.yml +++ b/.github/workflows/unit-test-on-pull-request.yml @@ -17,7 +17,7 @@ jobs: - name: Clone code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: go.mod cache-dependency-path: go.sum @@ -124,7 +124,7 @@ jobs: - name: Clone code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: go.mod cache-dependency-path: go.sum @@ -152,7 +152,6 @@ jobs: # https://github.com/cilium/ci-kernels/pkgs/container/ci-kernels/versions?filters%5Bversion_type%5D=tagged # AMD64 - - { target_arch: amd64, kernel: 5.4.276 } - { target_arch: amd64, kernel: 5.10.217 } - { target_arch: amd64, kernel: 5.15.159 } - { target_arch: amd64, kernel: 6.1.91 } @@ -281,7 +280,6 @@ jobs: strategy: matrix: include: - - { target_arch: amd64, kernel: 5.4.276 } - { target_arch: amd64, kernel: 5.10.217 } - { target_arch: amd64, kernel: 5.15.159 } - { target_arch: amd64, kernel: 6.1.91 } diff --git a/.github/workflows/unit-test-rust.yml b/.github/workflows/unit-test-rust.yml index 582baa313..56804a928 100644 --- a/.github/workflows/unit-test-rust.yml +++ b/.github/workflows/unit-test-rust.yml @@ -30,7 +30,7 @@ jobs: - name: Clone code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: targets: ${{ matrix.rust_target }} toolchain: 1.88.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2a2c6bc78..010fe205b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ slack channel for discussions and questions. ## Pre-requisites -- Linux (5.4+ for x86-64, 5.5+ for ARM64) with eBPF enabled (the profiler currently only runs on Linux) +- Linux (5.10+) with eBPF enabled (the profiler currently only runs on Linux) - Go as specified in [go.mod](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/blob/main/go.mod) - docker - Rust as specified in [Cargo.toml](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/blob/main/Cargo.toml) @@ -86,6 +86,25 @@ All pull requests are squashed to a single commit upon merge to `main`. [`draft`](https://github.blog/2019-02-14-introducing-draft-pull-requests/). * Make sure CLA is signed and CI is clear. +### How to Address Review Feedback + +Please use the GitHub UI to accept review suggestions that you don't +subsequently modify. Do not reimplement them in a separate commit. +The latter behavior is problematic as it: + +1. Increases burden on reviewers who have to spend additional time to check + that your reimplementation accurately reflects the original suggestion. +2. Increases the probability of bugs being introduced into the codebase. + This is not a theoretical concern as we've seen it happen multiple times. +3. Does not credit the reviewer who came up with the accepted suggestion. + +You can pull the GitHub-generated commits (after you've accepted a suggestion) +into your local repository by executing: + +```sh +git pull +``` + ### How to Get PRs Merged A PR is considered **ready to merge** when: diff --git a/Cargo.lock b/Cargo.lock index 39954e9a8..b1de06dfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,11 +37,11 @@ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -52,9 +52,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.57" +version = "1.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ "find-msvc-tools", "jobserver", @@ -70,13 +70,19 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cpp_demangle" version = "0.5.1" @@ -88,9 +94,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.17" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" dependencies = [ "libc", ] @@ -106,21 +112,21 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" dependencies = [ - "generic-array", - "typenum", + "hybrid-array", ] [[package]] name = "digest" -version = "0.10.7" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" dependencies = [ "block-buffer", + "const-oid", "crypto-common", ] @@ -186,16 +192,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.3.4" @@ -223,9 +219,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.33.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" +checksum = "19e16c5073773ccf057c282be832a59ee53ef5ff98db3aeff7f8314f52ffc196" dependencies = [ "fallible-iterator", "stable_deref_trait", @@ -252,6 +248,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hybrid-array" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +dependencies = [ + "typenum", +] + [[package]] name = "id-arena" version = "2.3.0" @@ -260,9 +265,9 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] name = "indexmap" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -312,9 +317,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "linux-raw-sys" @@ -367,9 +372,9 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "object" -version = "0.38.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" +checksum = "63944c133d03f44e75866bbd160b95af0ec3f6a13d936d69d31c81078cbc5baf" dependencies = [ "memchr", ] @@ -586,9 +591,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.9" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", "cpufeatures", @@ -603,9 +608,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "smallvec" @@ -715,12 +720,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" diff --git a/Cargo.toml b/Cargo.toml index 89510512c..1a148caa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ prost = "0.14.0" prost-build = "0.14.0" rustc-demangle = "0.1" serde_json = "1" -sha2 = "0.10" +sha2 = "0.11" tempfile = "3" thiserror = "2" zstd = "0.13.0" @@ -67,7 +67,7 @@ version = "0.16.0" default-features = false [workspace.dependencies.object] -version = "0.38.0" +version = "0.39.0" default-features = false features = ["std", "read_core", "elf", "macho", "unaligned"] diff --git a/Makefile b/Makefile index 24ab63b98..62c7e6d0c 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ ebpf-profiler: ebpf go build $(GO_FLAGS) -tags $(GO_TAGS) otelcol-ebpf-profiler: ebpf generate-collector - cd cmd/otelcol-ebpf-profiler/ && go build $(GO_FLAGS) -tags "$(GO_TAGS)" -o ../../$@ + cd cmd/otelcol-ebpf-profiler/ && go build $(GO_FLAGS) -tags "$(GO_TAGS)" -o ../../$@ # Sets opentelemetry collector modules to be pulled from local source tree. # This command allows you to make changes to your local checkout of otel core and build @@ -94,7 +94,7 @@ otelcol-ebpf-profiler: ebpf generate-collector # 2. Run `make otel-from-tree` (only need to run it once to remap go modules) # 3. You can now build collector and it will use your local otel core changes. # 4. Before committing/pushing your changes, undo by running `make otel-from-lib`. -otel-from-tree: +otel-from-tree: generate-collector ./cmd/otelcol-ebpf-profiler/otel-from-tree.sh # Removes local opentelemetry-collector replaces from manifest.yaml. diff --git a/README.md b/README.md index 93e9332c7..79134b9a5 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,7 @@ eBPF. ## Core features and strengths -- Implements the [experimental OTel profiling - signal](https://github.com/open-telemetry/opentelemetry-proto/pull/534) +- Implements the [Alpha OTel Profiles signal](https://github.com/open-telemetry/opentelemetry-proto/pull/775) - Very low CPU and memory overhead (1% CPU and 250MB memory are our upper limits in testing and the agent typically manages to stay way below that) - Support for native C/C++ executables without the need for DWARF debug @@ -19,22 +18,25 @@ eBPF. languages. - Support for native code (C/C++, Rust, Zig, Go, etc. without debug symbols on host) -- Support for a broad set of HLLs, like Hotspot JVM, Python, Ruby, PHP, Node.JS, V8, - Perl, Erlang and .NET. +- Support for a broad set of HLLs, like Hotspot JVM, Python, Ruby, PHP, Node.JS, + V8, Perl, Erlang and .NET. - 100% non-intrusive: there's no need to load agents or libraries into the processes that are being profiled. - No need for any reconfiguration, instrumentation or restarts of HLL interpreters and VMs: the agent supports unwinding each of the supported languages in the default configuration. -- ARM64 support for all unwinders except NodeJS. +- ARM64 support for all unwinders except .NET. - Support for native `inline frames`, which provide insights into compiler optimizations and offer a higher precision of function call chains. ## Building -We are working towards integrating the profiling functionality into the [OTel Collector](https://opentelemetry.io/docs/collector/) as a receiver, -which will be the supported configuration going forward. In the meantime, we also offer a standalone profiling agent binary named `ebpf-profiler`, -to aid with development and debugging. The expectation is that this will go away once the integration with the [OTel Collector](https://opentelemetry.io/docs/collector/) is complete. +We have integrated the profiler into the [OTel Collector](https://opentelemetry.io/docs/collector/) as a receiver, +and this is the [supported configuration](https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-ebpf-profiler) going forward. + +To aid with development, testing and debugging, we also offer a standalone profiling agent binary named `ebpf-profiler`, +and a local build of an OTel Collector profiling receiver binary (`otelcol-ebpf-profiler`). These binaries are not +supported in any way, can be dropped in the future and should not be deployed in production. ## Platform Requirements The agent can be built with the provided make targets. Docker is required for containerized builds, and both amd64 and arm64 architectures are supported. @@ -56,7 +58,16 @@ Since the profiler is Linux-only, macOS and Windows users need to set up a Linux ## Supported Linux kernel version -[7ddc23ea](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/commit/7ddc23ea135a2e00fffc17850ab90534e9b63108) is the last commit with support for 4.19. Changes after this commit may require a minimal Linux kernel version of 5.4. +The minimum required Linux kernel version has increased with certain commits. Specifically: + +- Commit [8047150e](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/commit/8047150e3f325f852874591356c69d0487b67d7c) was the last to support kernel version 5.4. Subsequent changes may require a minimal Linux kernel version of 5.10 or greater. +- Commit [7ddc23ea](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/commit/7ddc23ea135a2e00fffc17850ab90534e9b63108) was the last to support kernel version 4.19. Subsequent changes may require a minimal Linux kernel version of at least 5.4. + +### Updating the supported Linux kernel version + +The project maintains its minimum supported kernel version in line with the lowest kernel version currently provided by actively maintained major Linux distributions, which include Debian stable, Red Hat Enterprise Linux, Ubuntu LTS, Amazon Linux and SUSE Linux. The minimum requirement may be increased when all such distributions no longer ship a specific kernel version. This approach enables the codebase to utilize newer eBPF features and avoids the need to maintain compatibility shims for obsolete kernels. + +It should be noted that certain distributions incorporate eBPF features from newer kernels into their supported versions. When this occurs, the distribution's stated kernel version does not accurately reflect its true eBPF capabilities and will not prevent us from increasing the minimum supported version. On such kernels, the `no-kernel-version-check` configuration option can be used to bypass the checks and allow the profiler to execute. ## Alternative Build (Without Docker) You can build the agent without Docker by directly installing the dependencies listed in the Dockerfile. Once dependencies are set up, simply run: @@ -69,6 +80,18 @@ make debug ``` This will build the profiler natively on your machine. +## Building `otelcol-ebpf-profiler` locally (Without Docker) +You can build the local `otelcol-ebpf-profiler` binary by running: +```sh +make otelcol-ebpf-profiler +``` +or to cross-compile for a different architecture (e.g. arm64): +```sh +make otelcol-ebpf-profiler TARGET_ARCH=arm64 +``` + +See [local.example.yml](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/blob/main/cmd/otelcol-ebpf-profiler/local.example.yaml) for an example configuration. + ## Running You can start the agent with the following command: @@ -77,17 +100,29 @@ You can start the agent with the following command: sudo ./ebpf-profiler -collection-agent=127.0.0.1:11000 -disable-tls ``` +To start the OTel Collector profiling receiver, run: +```sh +sudo ./otelcol-ebpf-profiler --feature-gates=+service.profilesSupport --config cmd/otelcol-ebpf-profiler/local.example.yaml +``` + The agent comes with a functional but work-in-progress / evolving implementation -of the recently released OTel profiling [signal](https://github.com/open-telemetry/opentelemetry-proto/pull/534). +of the recently released Alpha OTel Profiles [signal](https://github.com/open-telemetry/opentelemetry-proto/pull/775). The agent loads the eBPF program and its maps, starts unwinding and reports captured traces to the backend. +## Open Source Backends +As the OTel Profiles signal is still in development, mature production-ready +backends have yet to emerge. To speed up development and experimentation, Elastic +has open-sourced a desktop application named [devfiler](https://github.com/elastic/devfiler) +that reimplements the backend (collection, data storage, symbolization and UI) +portion of the eBPF profiler. Note that devfiler is not a real production backend +and should not be used as such. It is solely aimed at testing, experimentation and development. + ## Development To understand how this project works and learn more about profiling, check out [Profiling internals](doc/internals.md) - # Legal ## Licensing Information diff --git a/cli_flags.go b/cli_flags.go index 5a16aa81c..3ca3db6f4 100644 --- a/cli_flags.go +++ b/cli_flags.go @@ -154,6 +154,8 @@ func parseArgs() (*controller.Config, error) { args.Fs = fs + args.ErrorMode = config.PropagateError + return &args, ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("OTEL_PROFILING_AGENT"), ff.WithConfigFileFlag("config"), diff --git a/cmd/otelcol-ebpf-profiler/manifest.yaml b/cmd/otelcol-ebpf-profiler/manifest.yaml index 32ecc7f27..9d3b09afd 100644 --- a/cmd/otelcol-ebpf-profiler/manifest.yaml +++ b/cmd/otelcol-ebpf-profiler/manifest.yaml @@ -13,19 +13,19 @@ dist: version: dev receivers: - - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.148.0 - - gomod: go.opentelemetry.io/ebpf-profiler v0.0.202610 + - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.149.0 + - gomod: go.opentelemetry.io/ebpf-profiler v0.0.202613 import: go.opentelemetry.io/ebpf-profiler/collector exporters: - - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.148.0 - - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.148.0 - - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.148.0 + - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.149.0 + - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.149.0 + - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.149.0 providers: - - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.54.0 - - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.54.0 - - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.54.0 + - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.55.0 + - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.55.0 + - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.55.0 replaces: - go.opentelemetry.io/ebpf-profiler => ../../ diff --git a/cmd/otelcol-ebpf-profiler/otel-from-tree.sh b/cmd/otelcol-ebpf-profiler/otel-from-tree.sh index 8be28ae99..3d78ebd88 100755 --- a/cmd/otelcol-ebpf-profiler/otel-from-tree.sh +++ b/cmd/otelcol-ebpf-profiler/otel-from-tree.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# NOTE: This script needs to be executed from the root directory +# of the repository. + set -euo pipefail # Use COLLECTOR_PATH if set, otherwise default to ../../../opentelemetry-collector @@ -15,12 +18,13 @@ fi echo " # START otel-from-tree - Do not edit below this line" >> cmd/otelcol-ebpf-profiler/manifest.yaml -grep -E "gomod: go.opentelemetry.io/collector/" cmd/otelcol-ebpf-profiler/manifest.yaml | \ - sed -E 's/.*gomod: ([^ ]+) .*/\1/' | \ - sort -u | \ - while read -r module; do - subpath=${module#go.opentelemetry.io/collector} - echo " - ${module} => ${COLLECTOR_PATH}${subpath}" >> cmd/otelcol-ebpf-profiler/manifest.yaml - done +# Replace collector module dependencies with local paths +cd cmd/otelcol-ebpf-profiler && go list -m -u all | \ + grep 'go\.opentelemetry\.io/collector' | \ + awk '{print $1}' | \ + while read -r module; do + subpath=${module#go.opentelemetry.io/collector} + echo " - ${module} => ${COLLECTOR_PATH}${subpath}" >> manifest.yaml + done echo "Local replaces added. You can now build with local opentelemetry-collector changes." diff --git a/collector/.gitignore b/collector/.gitignore new file mode 100644 index 000000000..dec1a32f6 --- /dev/null +++ b/collector/.gitignore @@ -0,0 +1 @@ +generated_*_test.go diff --git a/collector/README.md b/collector/README.md new file mode 100644 index 000000000..4b7ee3f82 --- /dev/null +++ b/collector/README.md @@ -0,0 +1,12 @@ +# eBPF Collector + + +| Status | | +| ------------- |-----------| +| Stability | [development]: profiles | +| Distributions | [ebpf-profiler] | +| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-ebpf-profiler?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fcollector%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fcollector) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-ebpf-profiler?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fcollector%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fcollector) | + +[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development +[ebpf-profiler]: + diff --git a/collector/config/config.go b/collector/config/config.go index 61aaf3de2..1f4ebe96d 100644 --- a/collector/config/config.go +++ b/collector/config/config.go @@ -6,7 +6,7 @@ package config // import "go.opentelemetry.io/ebpf-profiler/collector/config" import ( "errors" "fmt" - "runtime" + "strings" "time" "go.opentelemetry.io/ebpf-profiler/internal/linux" @@ -18,6 +18,27 @@ const ( MaxArgMapScaleFactor = 8 ) +// ErrorMode controls how the profiler receiver handles startup errors. +type ErrorMode string + +const ( + // IgnoreError means startup errors are logged but not returned to the collector. + IgnoreError ErrorMode = "ignore" + // PropagateError means startup errors are returned to the collector (default). + PropagateError ErrorMode = "propagate" +) + +func (e *ErrorMode) UnmarshalText(text []byte) error { + str := ErrorMode(strings.ToLower(string(text))) + switch str { + case IgnoreError, PropagateError: + *e = str + return nil + default: + return fmt.Errorf("unknown error mode %q", str) + } +} + // Config is the configuration for the collector. type Config struct { ReporterInterval time.Duration `mapstructure:"reporter_interval"` @@ -40,11 +61,16 @@ type Config struct { NoKernelVersionCheck bool `mapstructure:"no_kernel_version_check"` MaxGRPCRetries uint32 `mapstructure:"max_grpc_retries"` MaxRPCMsgSize int `mapstructure:"max_rpc_msg_size"` + ErrorMode ErrorMode `mapstructure:"error_mode"` } // Validate validates the config. // This is automatically called by the config parser as it implements the xconfmap.Validator interface. func (cfg *Config) Validate() error { + if cfg.ErrorMode != IgnoreError && cfg.ErrorMode != PropagateError { + return fmt.Errorf("unknown error mode %q", cfg.ErrorMode) + } + if cfg.SamplesPerSecond < 1 { return fmt.Errorf("invalid sampling frequency: %d", cfg.SamplesPerSecond) } @@ -95,17 +121,7 @@ func (cfg *Config) Validate() error { } var minMajor, minMinor uint32 - switch runtime.GOARCH { - case "amd64": - minMajor, minMinor = 5, 2 - case "arm64": - // Older ARM64 kernel versions have broken bpf_probe_read. - // https://github.com/torvalds/linux/commit/6ae08ae3dea2cfa03dd3665a3c8475c2d429ef47 - minMajor, minMinor = 5, 5 - default: - return fmt.Errorf("unsupported architecture: %s", runtime.GOARCH) - } - + minMajor, minMinor = 5, 10 if major < minMajor || (major == minMajor && minor < minMinor) { return fmt.Errorf("host Agent requires kernel version "+ "%d.%d or newer but got %d.%d.%d", minMajor, minMinor, major, minor, patch) diff --git a/collector/config/config_test.go b/collector/config/config_test.go index 63b27b237..441fcdefa 100644 --- a/collector/config/config_test.go +++ b/collector/config/config_test.go @@ -5,16 +5,111 @@ package config // import "go.opentelemetry.io/ebpf-profiler/collector/config" import ( "testing" + "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap/xconfmap" ) +// validConfig returns a config with valid defaults for testing. +func validConfig() *Config { + return &Config{ + SamplesPerSecond: 20, + ProbabilisticInterval: 1 * time.Minute, + ProbabilisticThreshold: 100, + NoKernelVersionCheck: true, + } +} + func TestValidate(t *testing.T) { cfg := &Config{ SamplesPerSecond: 0, + ErrorMode: PropagateError, } err := xconfmap.Validate(cfg) require.Error(t, err) require.Equal(t, "invalid sampling frequency: 0", err.Error()) } + +func TestUnmarshalText(t *testing.T) { + for _, tt := range []struct { + name string + input string + want ErrorMode + wantErr bool + }{ + { + name: "ignore", + input: "ignore", + want: IgnoreError, + }, + { + name: "propagate", + input: "propagate", + want: PropagateError, + }, + { + name: "case insensitive", + input: "IGNORE", + want: IgnoreError, + }, + { + name: "invalid value", + input: "INVALID", + wantErr: true, + }, + } { + t.Run(tt.name, func(t *testing.T) { + var e ErrorMode + err := e.UnmarshalText([]byte(tt.input)) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, e) + }) + } +} + +func TestValidateErrorMode(t *testing.T) { + for _, tt := range []struct { + name string + errorMode ErrorMode + want ErrorMode + wantErr bool + }{ + { + name: "empty error mode is invalid", + errorMode: "", + wantErr: true, + }, + { + name: "ignore is valid", + errorMode: IgnoreError, + want: IgnoreError, + }, + { + name: "propagate is valid", + errorMode: PropagateError, + want: PropagateError, + }, + { + name: "invalid error mode", + errorMode: "INVALID", + wantErr: true, + }, + } { + t.Run(tt.name, func(t *testing.T) { + cfg := validConfig() + cfg.ErrorMode = tt.errorMode + err := xconfmap.Validate(cfg) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, cfg.ErrorMode) + }) + } +} diff --git a/collector/factory.go b/collector/factory.go index 86c697585..1988b48ee 100644 --- a/collector/factory.go +++ b/collector/factory.go @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +//go:generate go tool -modfile=../tools.mod mdatagen metadata.yaml + package collector // import "go.opentelemetry.io/ebpf-profiler/collector" import ( @@ -12,20 +14,17 @@ import ( "go.opentelemetry.io/collector/receiver/xreceiver" "go.opentelemetry.io/ebpf-profiler/collector/config" + "go.opentelemetry.io/ebpf-profiler/collector/internal/metadata" ) -var ( - typeStr = component.MustNewType("profiling") - - errInvalidConfig = errors.New("invalid config") -) +var errInvalidConfig = errors.New("invalid config") // NewFactory creates a factory for the receiver. func NewFactory() receiver.Factory { return xreceiver.NewFactory( - typeStr, + metadata.Type, defaultConfig, - xreceiver.WithProfiles(BuildProfilesReceiver(), component.StabilityLevelAlpha)) + xreceiver.WithProfiles(BuildProfilesReceiver(), metadata.ProfilesStability)) } func defaultConfig() component.Config { @@ -40,5 +39,6 @@ func defaultConfig() component.Config { ClockSyncInterval: 3 * time.Minute, MaxGRPCRetries: 5, MaxRPCMsgSize: 32 << 20, // 32 MiB, + ErrorMode: config.PropagateError, } } diff --git a/collector/internal/controller.go b/collector/internal/controller.go index 2cf25bbd9..b76eabee6 100644 --- a/collector/internal/controller.go +++ b/collector/internal/controller.go @@ -9,8 +9,9 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/receiver" - + "go.opentelemetry.io/ebpf-profiler/collector/config" "go.opentelemetry.io/ebpf-profiler/internal/controller" + "go.opentelemetry.io/ebpf-profiler/internal/log" "go.opentelemetry.io/ebpf-profiler/metrics" "go.opentelemetry.io/ebpf-profiler/reporter" "go.opentelemetry.io/ebpf-profiler/times" @@ -22,10 +23,11 @@ const ( ) // Controller is a bridge between the Collector's [receiverprofiles.Profiles] -// interface and our [internal.Controller] +// interface and our [internal.Controller]. type Controller struct { ctlr *controller.Controller onShutdown func() error + errorMode config.ErrorMode } func NewController(cfg *controller.Config, rs receiver.Settings, @@ -64,12 +66,21 @@ func NewController(cfg *controller.Config, rs receiver.Settings, return &Controller{ onShutdown: cfg.OnShutdown, ctlr: controller.New(cfg), + errorMode: cfg.ErrorMode, }, nil } // Start starts the receiver. func (c *Controller) Start(ctx context.Context, _ component.Host) error { - return c.ctlr.Start(ctx) + if err := c.ctlr.Start(ctx); err != nil { + if c.errorMode == config.IgnoreError { + c.ctlr.Shutdown() + log.Errorf("eBPF profiler receiver failed, continuing without profiling: %v", err) + return nil + } + return err + } + return nil } // Shutdown stops the receiver. diff --git a/collector/internal/metadata/generated_status.go b/collector/internal/metadata/generated_status.go new file mode 100644 index 000000000..69b9d3d7b --- /dev/null +++ b/collector/internal/metadata/generated_status.go @@ -0,0 +1,16 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" +) + +var ( + Type = component.MustNewType("profiling") + ScopeName = "go.opentelemetry.io/ebpf-profiler/collector" +) + +const ( + ProfilesStability = component.StabilityLevelDevelopment +) diff --git a/collector/metadata.yaml b/collector/metadata.yaml new file mode 100644 index 000000000..bc68abc7f --- /dev/null +++ b/collector/metadata.yaml @@ -0,0 +1,11 @@ +type: profiling +github_project: open-telemetry/opentelemetry-ebpf-profiler + +status: + disable_codecov_badge: true + class: receiver + stability: + development: [profiles] + distributions: [ebpf-profiler] +tests: + skip_lifecycle: true diff --git a/collector/start_test.go b/collector/start_test.go new file mode 100644 index 000000000..cd0128905 --- /dev/null +++ b/collector/start_test.go @@ -0,0 +1,82 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:build linux && (amd64 || arm64) + +package collector + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/consumer/xconsumer" + "go.opentelemetry.io/collector/receiver/receivertest" + + "go.opentelemetry.io/ebpf-profiler/collector/config" + "go.opentelemetry.io/ebpf-profiler/libpf" + "go.opentelemetry.io/ebpf-profiler/reporter" + "go.opentelemetry.io/ebpf-profiler/reporter/samples" +) + +// dummyReporter is a no-op reporter for testing. +type dummyReporter struct{} + +func (d *dummyReporter) Start(context.Context) error { return fmt.Errorf("dummy error") } +func (d *dummyReporter) Stop() {} +func (d *dummyReporter) ReportTraceEvent(*libpf.Trace, *samples.TraceEventMeta) error { return nil } + +// TestStartErrorMode tests the error_mode config option on controller Start(). +// dummyReporter.Start() always returns an error to simulate startup failure. +func TestStartErrorMode(t *testing.T) { + dummyFactory := func(_ *reporter.Config, _ xconsumer.Profiles) (reporter.Reporter, error) { + return &dummyReporter{}, nil + } + + for _, tt := range []struct { + name string + errorMode config.ErrorMode + wantErr bool + }{ + { + name: "propagate returns error", + errorMode: config.PropagateError, + wantErr: true, + }, + { + name: "ignore returns nil", + errorMode: config.IgnoreError, + wantErr: false, + }, + } { + t.Run(tt.name, func(t *testing.T) { + cfg := defaultConfig().(*config.Config) + cfg.ErrorMode = tt.errorMode + cfg.NoKernelVersionCheck = true + + typ, err := component.NewType("test") + require.NoError(t, err) + + recv, err := BuildProfilesReceiver( + WithReporterFactory(dummyFactory), + )( + t.Context(), + receivertest.NewNopSettings(typ), + cfg, + consumertest.NewNop(), + ) + require.NoError(t, err) + + err = recv.Start(t.Context(), componenttest.NewNopHost()) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/doc/KNOWN_KERNEL_LIMITATIONS.md b/doc/KNOWN_KERNEL_LIMITATIONS.md deleted file mode 100644 index 030f0fd81..000000000 --- a/doc/KNOWN_KERNEL_LIMITATIONS.md +++ /dev/null @@ -1,33 +0,0 @@ -Known limitations -================= -The Linux kernel is constantly evolving and so is eBPF. To be able to load our eBPF code with older kernel versions we have to write code to avoid some limitations. This file documents the restrictions we ran into while writing the code. - -Number of tracepoints ---------------------- -Affects kernel < 4.15. - -There was a limit of 1 eBPF program per tracepoint/kprobe. -This limit no longer holds and was removed with commit [e87c6bc3852b981e71c757be20771546ce9f76f3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e87c6bc3852b981e71c757be20771546ce9f76f3). - - -Kernel version check --------------------- -Affects kernel < 5.0. - -As part of the verification of eBPF programs, the `kern_version` attribute was checked and it needed to match with the currently running kernel version. -This check was removed with commit [6c4fc209fcf9d27efbaa48368773e4d2bfbd59aa](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6c4fc209fcf9d27efbaa48368773e4d2bfbd59aa). - - -eBPF instruction limit ----------------------- -Affects kernel < 5.2. - -The number of eBPF instructions per program was limited to 4096 instructions. -This limit was raised to 1 million eBPF instructions with commit [c04c0d2b968ac45d6ef020316808ef6c82325a82](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c04c0d2b968ac45d6ef020316808ef6c82325a82). - - -eBPF inner arrays (map-in-map) must be of same size ---------------------------------------------------- -Affects kernel < 5.10. - -This restriction was removed with commit[4a8f87e60f6db40e640f1db555d063b2c4dea5f1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4a8f87e60f6db40e640f1db555d063b2c4dea5f1). diff --git a/doc/internals.md b/doc/internals.md index a0a52fc2e..299698a97 100644 --- a/doc/internals.md +++ b/doc/internals.md @@ -206,16 +206,10 @@ of these limitations are significantly relaxed in newer kernel versions, but we still have to stick to the old limits because we wish to continue supporting older kernels. -The minimum supported Linux kernel versions are -- 5.4 for amd64/x86_64 -- 5.5 for arm64/aarch64 +The minimum supported Linux kernel versions is 5.10 for amd64/x86_64 and arm64/aarch64. The most notable limitations are the following two: -- **4096 instructions per program**\ - A single BPF program can consist of a maximum of 4096 instructions, otherwise - older kernels will refuse to load it. Since BPF does not allow for loops, they - instead need to be unrolled. - **32 tail-calls**\ Linux allows BPF programs to do a tail-call to another BPF program. A tail call is essentially a `jmp` into another BPF program, ending execution of the diff --git a/go.mod b/go.mod index b2ae917e7..5ef809397 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,9 @@ module go.opentelemetry.io/ebpf-profiler go 1.25.0 require ( - github.com/aws/aws-sdk-go-v2 v1.41.4 - github.com/aws/aws-sdk-go-v2/config v1.32.12 - github.com/aws/aws-sdk-go-v2/service/s3 v1.97.2 + github.com/aws/aws-sdk-go-v2 v1.41.5 + github.com/aws/aws-sdk-go-v2/config v1.32.14 + github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0 github.com/cilium/ebpf v0.21.0 github.com/coreos/pkg v0.0.0-20240122114842-bbd7aa9bf6fb github.com/elastic/go-freelru v0.16.0 @@ -31,25 +31,28 @@ require ( github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.42.0 github.com/zeebo/xxh3 v1.1.0 - go.opentelemetry.io/collector/component v1.54.0 - go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 - go.opentelemetry.io/collector/consumer/consumertest v0.148.0 - go.opentelemetry.io/collector/consumer/xconsumer v0.148.0 - go.opentelemetry.io/collector/pdata v1.54.0 - go.opentelemetry.io/collector/pdata/pprofile v0.148.0 - go.opentelemetry.io/collector/receiver v1.54.0 - go.opentelemetry.io/collector/receiver/receivertest v0.148.0 - go.opentelemetry.io/collector/receiver/xreceiver v0.148.0 - go.opentelemetry.io/otel v1.42.0 - go.opentelemetry.io/otel/metric v1.42.0 + go.opentelemetry.io/collector/component v1.55.0 + go.opentelemetry.io/collector/component/componenttest v0.149.0 + go.opentelemetry.io/collector/confmap v1.55.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.149.0 + go.opentelemetry.io/collector/consumer/consumertest v0.149.0 + go.opentelemetry.io/collector/consumer/xconsumer v0.149.0 + go.opentelemetry.io/collector/pdata v1.55.0 + go.opentelemetry.io/collector/pdata/pprofile v0.149.0 + go.opentelemetry.io/collector/receiver v1.55.0 + go.opentelemetry.io/collector/receiver/receivertest v0.149.0 + go.opentelemetry.io/collector/receiver/xreceiver v0.149.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/metric v1.43.0 go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 + go.uber.org/goleak v1.3.0 go.uber.org/zap/exp v0.3.0 golang.org/x/arch v0.25.0 golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 golang.org/x/mod v0.34.0 golang.org/x/sync v0.20.0 golang.org/x/sys v0.42.0 - google.golang.org/grpc v1.79.3 + google.golang.org/grpc v1.80.0 google.golang.org/protobuf v1.36.11 ) @@ -58,20 +61,20 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.19.12 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.14 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 // indirect github.com/aws/smithy-go v1.24.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -100,7 +103,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect github.com/knadh/koanf/providers/confmap v1.0.0 // indirect - github.com/knadh/koanf/v2 v2.3.3 // indirect + github.com/knadh/koanf/v2 v2.3.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/mdlayher/netlink v1.7.2 // indirect @@ -126,17 +129,15 @@ require ( github.com/tklauser/numcpus v0.11.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/collector/component/componenttest v0.148.0 // indirect - go.opentelemetry.io/collector/confmap v1.54.0 // indirect - go.opentelemetry.io/collector/consumer v1.54.0 // indirect - go.opentelemetry.io/collector/consumer/consumererror v0.148.0 // indirect - go.opentelemetry.io/collector/featuregate v1.54.0 // indirect - go.opentelemetry.io/collector/internal/componentalias v0.148.0 // indirect - go.opentelemetry.io/collector/pipeline v1.54.0 // indirect + go.opentelemetry.io/collector/consumer v1.55.0 // indirect + go.opentelemetry.io/collector/consumer/consumererror v0.149.0 // indirect + go.opentelemetry.io/collector/featuregate v1.55.0 // indirect + go.opentelemetry.io/collector/internal/componentalias v0.149.0 // indirect + go.opentelemetry.io/collector/pipeline v1.55.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/otel/sdk v1.42.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.42.0 // indirect - go.opentelemetry.io/otel/trace v1.42.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect diff --git a/go.sum b/go.sum index a716c3390..a1b66a466 100644 --- a/go.sum +++ b/go.sum @@ -6,42 +6,42 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k= -github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= +github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= -github.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0= -github.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g= -github.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8= -github.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc= +github.com/aws/aws-sdk-go-v2/config v1.32.14 h1:opVIRo/ZbbI8OIqSOKmpFaY7IwfFUOCCXBsUpJOwDdI= +github.com/aws/aws-sdk-go-v2/config v1.32.14/go.mod h1:U4/V0uKxh0Tl5sxmCBZ3AecYny4UNlVmObYjKuuaiOo= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21 h1:SwGMTMLIlvDNyhMteQ6r8IJSBPlRdXX5d4idhIGbkXA= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21/go.mod h1:UUxgWxofmOdAMuqEsSppbDtGKLfR04HGsD0HXzvhI1k= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 h1:rWyie/PxDRIdhNf4DzRk0lvjVOqFJuNnO8WwaIRVxzQ= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22/go.mod h1:zd/JsJ4P7oGfUhXn1VyLqaRZwPmZwg44Jf2dS84Dm3Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12 h1:qtJZ70afD3ISKWnoX3xB0J2otEqu3LqicRcDBqsj0hQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12/go.mod h1:v2pNpJbRNl4vEUWEh5ytQok0zACAKfdmKS51Hotc3pQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20 h1:siU1A6xjUZ2N8zjTHSXFhB9L/2OY8Dqs0xXiLjF30jA= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20/go.mod h1:4TLZCmVJDM3FOu5P5TJP0zOlu9zWgDWU7aUxWbr+rcw= -github.com/aws/aws-sdk-go-v2/service/s3 v1.97.2 h1:MRNiP6nqa20aEl8fQ6PJpEq11b2d40b16sm4WD7QgMU= -github.com/aws/aws-sdk-go-v2/service/s3 v1.97.2/go.mod h1:FrNA56srbsr3WShiaelyWYEo70x80mXnVZ17ZZfbeqg= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 h1:JRaIgADQS/U6uXDqlPiefP32yXTda7Kqfx+LgspooZM= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13/go.mod h1:CEuVn5WqOMilYl+tbccq8+N2ieCy0gVn3OtRb0vBNNM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 h1:ZlvrNcHSFFWURB8avufQq9gFsheUgjVD9536obIknfM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21/go.mod h1:cv3TNhVrssKR0O/xxLJVRfd2oazSnZnkUeTf6ctUwfQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0 h1:foqo/ocQ7WqKwy3FojGtZQJo0FR4vto9qnz9VaumbCo= +github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0/go.mod h1:uoA43SdFwacedBfSgfFSjjCvYe8aYBS7EnU5GZ/YKMM= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 h1:lFd1+ZSEYJZYvv9d6kXzhkZu07si3f+GQ1AaYwa2LUM= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 h1:dzztQ1YmfPrxdrOiuZRMF6fuOwWlWpD2StNLTceKpys= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw= github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -133,8 +133,8 @@ github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpb github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE= github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A= -github.com/knadh/koanf/v2 v2.3.3 h1:jLJC8XCRfLC7n4F+ZKKdBsbq1bfXTpuFhf4L7t94D94= -github.com/knadh/koanf/v2 v2.3.3/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= +github.com/knadh/koanf/v2 v2.3.4 h1:fnynNSDlujWE+v83hAp8wKr/cdoxHLO0629SN+U8Urc= +github.com/knadh/koanf/v2 v2.3.4/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -227,54 +227,54 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= 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/collector/component v1.54.0 h1:LvtX0Tzz18n44OrUFVk77N1FNsejfWJqztB28hrmDM8= -go.opentelemetry.io/collector/component v1.54.0/go.mod h1:yUMBYsySY/sDcXm8kOzEoZxt+JLdala6hxzSW0npOxY= -go.opentelemetry.io/collector/component/componenttest v0.148.0 h1:tBXJWmy2X6KD8S0QU2YZa2zYBqP+IycSM4iOtwDD2pA= -go.opentelemetry.io/collector/component/componenttest v0.148.0/go.mod h1:1c1+6mZOmI0raoya5vA/X0F+fawEjNS6tCEs5xLATtA= -go.opentelemetry.io/collector/confmap v1.54.0 h1:RUoxQ4uAYHTI57GfHh61D00tTQsXm9T88ozrAiicByc= -go.opentelemetry.io/collector/confmap v1.54.0/go.mod h1:mQxG8bk0IWIt9gbWMvzE+cRkOuCuzbzkNGBq2YJ4wNM= -go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 h1:UW8MX5VlKJf67x4Et7J9kPwP9Rv4VSmJ+UUpgRcb//c= -go.opentelemetry.io/collector/confmap/xconfmap v0.148.0/go.mod h1:4qTMr3V0uSXXac9wVs/UD5fIqRKw5yIl58+Vjsc6RHM= -go.opentelemetry.io/collector/consumer v1.54.0 h1:RGGtUN+GbkV1px3T6XdUHmgJ+ldJ1hAHdesFzW/wgL0= -go.opentelemetry.io/collector/consumer v1.54.0/go.mod h1:1PC6XINTL9DdT1bwvfMdHE72EB4RWU/WcPemUrhqKN8= -go.opentelemetry.io/collector/consumer/consumererror v0.148.0 h1:lKVkNWBeRXG41lHBf5KzA9oErRZifx6qTd9erAFfEkE= -go.opentelemetry.io/collector/consumer/consumererror v0.148.0/go.mod h1:N/UppmtknIdzpEiy3xirH1EiBEBOqKqD77NCyNi2Rbc= -go.opentelemetry.io/collector/consumer/consumertest v0.148.0 h1:ms0HtWMj17tI1Yds0hSuUI5QYpNEqd11AAhwIoUY2HE= -go.opentelemetry.io/collector/consumer/consumertest v0.148.0/go.mod h1:wScw/OzKkf/ZzJn4ToI30OoI1kJiY16WNrcFToXSzK0= -go.opentelemetry.io/collector/consumer/xconsumer v0.148.0 h1:m3b9rY7CLD5Pcge6sSKHIT3OlcPN6xqYsdtVs9oJ528= -go.opentelemetry.io/collector/consumer/xconsumer v0.148.0/go.mod h1:bG+Wz6xmIBl/gHzq1sqvksWXqTLuTX17Wo//zIsdZpw= -go.opentelemetry.io/collector/featuregate v1.54.0 h1:ufo5Hy4Co9pcHVg24hyanm8qFG3TkkYbVyQXPVAbwDc= -go.opentelemetry.io/collector/featuregate v1.54.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g= -go.opentelemetry.io/collector/internal/componentalias v0.148.0 h1:Y6MftNIZSzOr47TTj6A2z2UR3IwbeG46sAQshicGtDg= -go.opentelemetry.io/collector/internal/componentalias v0.148.0/go.mod h1:uwKzfehzwRgHxdHgFXYSBHNBeWSSqsqQYGWr5fk08G0= -go.opentelemetry.io/collector/internal/testutil v0.148.0 h1:3Z9hperte3vSmbBTYeNndoEUICICrNz8hzx+v0FYXBQ= -go.opentelemetry.io/collector/internal/testutil v0.148.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= -go.opentelemetry.io/collector/pdata v1.54.0 h1:3LharKb792cQ3VrUGxd3IcpWwfu3ST+GSTU382jVz1s= -go.opentelemetry.io/collector/pdata v1.54.0/go.mod h1:+MqC3VVOv/EX9YVFUo+mI4F0YmwJ+fXBYwjmu+mRiZ8= -go.opentelemetry.io/collector/pdata/pprofile v0.148.0 h1:MgrNZmqwhZGfiYwcKKtM/iXgTZqqvG5dUphriRXMZHU= -go.opentelemetry.io/collector/pdata/pprofile v0.148.0/go.mod h1:MTTMnZPqWX1S/rBDatU0W19udlycBkWuzVV5qnemHdc= -go.opentelemetry.io/collector/pdata/testdata v0.148.0 h1:yzakPuFgoKK8WcrlhyYHLMLA/kLScQKGsXkIgwieAQ8= -go.opentelemetry.io/collector/pdata/testdata v0.148.0/go.mod h1:2rFvxm8qwd3nlO90FtJw6ZGAjt+bLndxmQuJaMO9kfQ= -go.opentelemetry.io/collector/pipeline v1.54.0 h1:jYlCkdFLITVBdeB+IGS07zXWywEgvT3Ky46vdKKT+Ks= -go.opentelemetry.io/collector/pipeline v1.54.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs= -go.opentelemetry.io/collector/receiver v1.54.0 h1:2e9o+eihZ/nJnzVj5JAcJ+VQ653HcZRiT127qBZRqa8= -go.opentelemetry.io/collector/receiver v1.54.0/go.mod h1:xFZnvYTBjdi9iS/d/UUXzss4h311mLsZliQFQXk4o/k= -go.opentelemetry.io/collector/receiver/receivertest v0.148.0 h1:Fu+B4jCqgZVZmhsKBz3tcgimFryR6TRAK2D5VGLD2Xc= -go.opentelemetry.io/collector/receiver/receivertest v0.148.0/go.mod h1:K8dMDMEggEg6jB688VOHutivOGEEZ20FJGe4jV9RtWU= -go.opentelemetry.io/collector/receiver/xreceiver v0.148.0 h1:u66Zi3udD9RMRiNOsZzsVcUjRwqJEK+5LV76Ry9l3K0= -go.opentelemetry.io/collector/receiver/xreceiver v0.148.0/go.mod h1:jyHxf8SOfH48ZXb32IS3vPbVYDinsLlZYQddyrveqMg= +go.opentelemetry.io/collector/component v1.55.0 h1:45nb42/UqPDhRdS8FgGRDybRsWSuvS+r6WC2VTVqIRw= +go.opentelemetry.io/collector/component v1.55.0/go.mod h1:7EpGxVpqFkZ2HidyiE9MLvh4cuKU7ye6i5OtxxiYKps= +go.opentelemetry.io/collector/component/componenttest v0.149.0 h1:7SSYIiLpe84LGfYAp7RCkzYuYLuYVSZVn/K/qsJZgHY= +go.opentelemetry.io/collector/component/componenttest v0.149.0/go.mod h1:8xPU3XMsI+J4vfy87YG1bsCVTeedligKWgBcPEZ0yzw= +go.opentelemetry.io/collector/confmap v1.55.0 h1:pBJbjWfIT3q8cy+eVcHCCYXx984NxOjaGTHqIWsXC1A= +go.opentelemetry.io/collector/confmap v1.55.0/go.mod h1:rSKNE5ztWU6fS0pT8rwACn573r4jJc4QzJyoQzZIVtE= +go.opentelemetry.io/collector/confmap/xconfmap v0.149.0 h1:D/WzrxKOKedRztoY/MiAj9z8W0/2unpTCbANFCwvuuY= +go.opentelemetry.io/collector/confmap/xconfmap v0.149.0/go.mod h1:lJ1nHIQbH6L5wnj5vTWGr7RWi5Kib2KX5stAxar13Jo= +go.opentelemetry.io/collector/consumer v1.55.0 h1:7Per8P4J0nlBrFVSXb+nwZ+egiel1BRtggZngyykGsM= +go.opentelemetry.io/collector/consumer v1.55.0/go.mod h1:Qrn5fDp/HpDmUp+l2RGKsdKyOPlgGlaZPKvw/z9FfEc= +go.opentelemetry.io/collector/consumer/consumererror v0.149.0 h1:lXJv8UySfvnISJnCbkxf9ghYRQoWcXC78PxGurdnhKY= +go.opentelemetry.io/collector/consumer/consumererror v0.149.0/go.mod h1:8mZKwHejnZpD0+hjg6T2ZYPzs/Ib8512DMFnx4yaknY= +go.opentelemetry.io/collector/consumer/consumertest v0.149.0 h1:IxOkDInfuUM8mT+rMNGtdUuuDlV9X2VS4WAQ/dZSYqg= +go.opentelemetry.io/collector/consumer/consumertest v0.149.0/go.mod h1:ZMvFzch5IRjYBvj6WPc30HRy19smS0WFBXaOu16Wac0= +go.opentelemetry.io/collector/consumer/xconsumer v0.149.0 h1:2z0wRTDsWqPdcC8xp9HJIAJej+07g4/yJrS0xkJJ4hA= +go.opentelemetry.io/collector/consumer/xconsumer v0.149.0/go.mod h1:AG9w3bk38dq3Rk7C2JGf3jw4ldxR063ujYBm3eiMJ7k= +go.opentelemetry.io/collector/featuregate v1.55.0 h1:s/bE8135+8GZpVlQ9qLXQjvprE9KNOGsLhNkqm+EDEU= +go.opentelemetry.io/collector/featuregate v1.55.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g= +go.opentelemetry.io/collector/internal/componentalias v0.149.0 h1:0cH1hCy4vujhnAc6z4baLM0mauFZPfyqF9HtQF6YvGo= +go.opentelemetry.io/collector/internal/componentalias v0.149.0/go.mod h1:8oIpxyFLZECp6O7zFDTGeWw72CQ67C8wb6FqAL9wvCo= +go.opentelemetry.io/collector/internal/testutil v0.149.0 h1:OWfUPO3NFKSaJtz/SBZph/2ENHbr/VbzzlBadKUhm8o= +go.opentelemetry.io/collector/internal/testutil v0.149.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= +go.opentelemetry.io/collector/pdata v1.55.0 h1:WBgye8bo8koUyV9Vmp/r2Q3lgDezdsgfKDQAaM1oT2I= +go.opentelemetry.io/collector/pdata v1.55.0/go.mod h1:6jPrbM4tuliCPACDznjFtxnnHisfKfzwrBVoeuESYuk= +go.opentelemetry.io/collector/pdata/pprofile v0.149.0 h1:4/uI7wsgMnmBZm6Z/VNY6sWnaFN09+Nk3jr7XEmTtOk= +go.opentelemetry.io/collector/pdata/pprofile v0.149.0/go.mod h1:4uprs5wMp4MI1/bcP5mYERfobFxBn+QoeNFQBUSVk/U= +go.opentelemetry.io/collector/pdata/testdata v0.149.0 h1:Y9WCJpr9fvpCGmvh6wK0i+QtOn0OyGXnoOkLfq7xtok= +go.opentelemetry.io/collector/pdata/testdata v0.149.0/go.mod h1:5BscHKM7cy9lzPMpnaIFaTOMI8SI02AsEF4rH3aRJBg= +go.opentelemetry.io/collector/pipeline v1.55.0 h1:jxFicLy3QYWQaQZp2f+wdCfHpOYb3mKNTqHR1KIut+U= +go.opentelemetry.io/collector/pipeline v1.55.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs= +go.opentelemetry.io/collector/receiver v1.55.0 h1:7GVQOPleD60LzxvkqHaChlbWw5nJvw6i2fV6UBL+7EQ= +go.opentelemetry.io/collector/receiver v1.55.0/go.mod h1:Sdx1R+nh6p9lQSZJk8KfQK4nzLI4zNrceIk7a8WpSQg= +go.opentelemetry.io/collector/receiver/receivertest v0.149.0 h1:S33+mAxh7QTxY2o0fTFKEN/ULgcuw36hUVQDyIlSpTc= +go.opentelemetry.io/collector/receiver/receivertest v0.149.0/go.mod h1:w+W/7Dd64jHeCsQcJZBB6oSz3gasvKz5KP1yKzaN8V8= +go.opentelemetry.io/collector/receiver/xreceiver v0.149.0 h1:EpJ5zqTrJwQT1QsX+JHRcDfTA1Mzf0gAOPGihkxtn7E= +go.opentelemetry.io/collector/receiver/xreceiver v0.149.0/go.mod h1:hoUUGXcIr7ZuDdkqzLGfy5P7Njsc/YQ8riWX70Ukf6E= 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.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= -go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= -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 v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= 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/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 h1:ZQs05qo3Yh4KUHeVH6v89xErwmsvgA/cLX2/w5Ikp+k= @@ -329,12 +329,12 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/interpreter/beam/beam.go b/interpreter/beam/beam.go index ab72f280f..47d392b39 100644 --- a/interpreter/beam/beam.go +++ b/interpreter/beam/beam.go @@ -337,7 +337,7 @@ func (d *beamData) Attach(ebpf interpreter.EbpfHandler, pid libpf.PID, bias libp func (d *beamData) Unload(_ interpreter.EbpfHandler) { } -func (i *beamInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler, _ reporter.ExecutableReporter, pr process.Process, mappings []process.Mapping) error { +func (i *beamInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler, _ reporter.ExecutableReporter, pr process.Process, mappings []process.RawMapping) error { pid := pr.PID() i.mappingGeneration++ for idx := range mappings { diff --git a/interpreter/dotnet/instance.go b/interpreter/dotnet/instance.go index 1f36524b4..a556401f8 100644 --- a/interpreter/dotnet/instance.go +++ b/interpreter/dotnet/instance.go @@ -141,7 +141,7 @@ type dotnetInstance struct { virtualCallStubManagerManagerPtr libpf.Address // mappings contains the PE mappings to process memory space. Multiple individual - // consecutive process.Mappings may be merged to one mapping per PE file. + // consecutive process.RawMappings may be merged to one mapping per PE file. mappings []dotnetMapping ranges map[libpf.Address]dotnetRangeSection @@ -552,7 +552,7 @@ func (i *dotnetInstance) getDacSlotPtr(slot uint) libpf.Address { func (i *dotnetInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler, exeReporter reporter.ExecutableReporter, pr process.Process, - mappings []process.Mapping, + mappings []process.RawMapping, ) error { // get introspection data cdac, err := i.d.GetOrInit(func() (dotnetCdac, error) { return i.d.newVMData(i.rm, i.bias) }) @@ -599,7 +599,7 @@ func (i *dotnetInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler, if m.IsAnonymous() { continue } - if !strings.HasSuffix(m.Path.String(), ".dll") { + if !strings.HasSuffix(m.Path, ".dll") { continue } diff --git a/interpreter/dotnet/pe.go b/interpreter/dotnet/pe.go index 952a92e76..fde83feb4 100644 --- a/interpreter/dotnet/pe.go +++ b/interpreter/dotnet/pe.go @@ -1209,7 +1209,7 @@ func (pc *peCache) init() { pc.peInfoCache = peInfoCache } -func (pc *peCache) Get(pr process.Process, mapping *process.Mapping) *peInfo { +func (pc *peCache) Get(pr process.Process, mapping *process.RawMapping) *peInfo { key := mapping.GetOnDiskFileIdentifier() lastModified := pr.GetMappingFileLastModified(mapping) if info, ok := pc.peInfoCache.Get(key); ok && info.lastModified == lastModified { @@ -1243,7 +1243,7 @@ func (pc *peCache) Get(pr process.Process, mapping *process.Mapping) *peInfo { if info.err == nil { mf := libpf.NewFrameMappingFile(libpf.FrameMappingFileData{ FileID: fileID, - FileName: libpf.Intern(path.Base(mapping.Path.String())), + FileName: libpf.Intern(path.Base(mapping.Path)), GnuBuildID: info.guid, }) info.mapping = libpf.NewFrameMapping(libpf.FrameMappingData{ diff --git a/interpreter/go/go_test.go b/interpreter/go/go_test.go index 03e547782..7744d96d0 100644 --- a/interpreter/go/go_test.go +++ b/interpreter/go/go_test.go @@ -49,7 +49,7 @@ func BenchmarkGolang(b *testing.B) { } frames := libpf.Frames{} - ef := libpf.NewEbpfFrame(libpf.NativeFrame, 0, 1, uint64(pc)) + ef := libpf.NewEbpfFrame(libpf.NativeFrame, 0, 2, uint64(pc)) ef[1] = uint64(hostFileID) if err := gI.Symbolize(ef, &frames, libpf.FrameMapping{}); err != nil { diff --git a/interpreter/golabels/golabels.go b/interpreter/golabels/golabels.go index 71e00e284..1e733d0a6 100644 --- a/interpreter/golabels/golabels.go +++ b/interpreter/golabels/golabels.go @@ -4,6 +4,7 @@ package golabels // import "go.opentelemetry.io/ebpf-profiler/interpreter/golabels" import ( + "debug/elf" "errors" "fmt" "go/version" @@ -59,6 +60,25 @@ func Loader(_ interpreter.EbpfHandler, info *interpreter.LoaderInfo) (interprete return nil, nil } + // Go plugins are shared objects that share the runtime with the main + // binary. The offsets we need are determined by the main binary so + // there is no reason to create a duplicate golabels instance for + // a plugin. A shared library is ET_DYN without a PT_INTERP segment + // (PIE executables are also ET_DYN but have PT_INTERP). + if file.Type == elf.ET_DYN { + hasInterp := false + for i := range file.Progs { + if file.Progs[i].Type == elf.PT_INTERP { + hasInterp = true + break + } + } + if !hasInterp { + log.Debugf("file %s is a Go shared library, skipping golabels", info.FileName()) + return nil, nil + } + } + if version.Compare(goVersion, "go1.27") >= 0 { return nil, fmt.Errorf("unsupported Go version %s (need >= 1.13 and <= 1.26)", goVersion) } diff --git a/interpreter/hotspot/instance.go b/interpreter/hotspot/instance.go index ce0802f68..e116b772e 100644 --- a/interpreter/hotspot/instance.go +++ b/interpreter/hotspot/instance.go @@ -854,7 +854,7 @@ func (d *hotspotInstance) updateStubMappings(vmd *hotspotVMData, } func (d *hotspotInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler, - _ reporter.ExecutableReporter, pr process.Process, _ []process.Mapping, + _ reporter.ExecutableReporter, pr process.Process, _ []process.RawMapping, ) error { vmd, err := d.d.GetOrInit(func() (hotspotVMData, error) { return d.d.newVMData(d.rm, d.bias) }) if err != nil { diff --git a/interpreter/instancestubs.go b/interpreter/instancestubs.go index d3e7eb99b..75eb28417 100644 --- a/interpreter/instancestubs.go +++ b/interpreter/instancestubs.go @@ -23,7 +23,7 @@ type InstanceStubs struct { } func (is *InstanceStubs) SynchronizeMappings(EbpfHandler, reporter.ExecutableReporter, - process.Process, []process.Mapping) error { + process.Process, []process.RawMapping) error { return nil } diff --git a/interpreter/luajit/luajit.go b/interpreter/luajit/luajit.go index 600e3a1e7..f881dd1ee 100644 --- a/interpreter/luajit/luajit.go +++ b/interpreter/luajit/luajit.go @@ -39,7 +39,7 @@ type vmMap map[libpf.Address]struct{} // Records all the JIT regions we've seen, value is SynchronizeMappings // generation. -type regionMap map[process.Mapping]int +type regionMap map[process.RawMapping]int type regionKey struct { start, end uint64 @@ -236,12 +236,12 @@ func (l *luajitInstance) addTrace(ebpf interpreter.EbpfHandler, pid libpf.PID, t } func (l *luajitInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler, - _ reporter.ExecutableReporter, pr process.Process, mappings []process.Mapping) error { + _ reporter.ExecutableReporter, pr process.Process, mappings []process.RawMapping) error { return l.synchronizeMappings(ebpf, pr.PID(), mappings) } func (l *luajitInstance) synchronizeMappings(ebpf interpreter.EbpfHandler, pid libpf.PID, - mappings []process.Mapping) error { + mappings []process.RawMapping) error { cycle := l.cycle l.cycle++ for i := range mappings { diff --git a/interpreter/luajit/mappings_test.go b/interpreter/luajit/mappings_test.go index b4b92f35d..0e921bc73 100644 --- a/interpreter/luajit/mappings_test.go +++ b/interpreter/luajit/mappings_test.go @@ -49,13 +49,13 @@ func (m *ebpfMapsMockup) DeletePidInterpreterMapping(pid libpf.PID, pfx lpm.Pref // TestSynchronizeMappings tests that if a mapping is realloc'd we do the right thing. func TestSynchronizeMappings(t *testing.T) { for _, tc := range []struct { - calls []process.Mapping + calls []process.RawMapping }{ - {[]process.Mapping{ + {[]process.RawMapping{ {Vaddr: 0x2000, Length: 0x1000, Flags: elf.PF_X}, {Vaddr: 0x1000, Length: 0x2000, Flags: elf.PF_X}, }}, - {[]process.Mapping{ + {[]process.RawMapping{ {Vaddr: 0x2000, Length: 0x1000, Flags: elf.PF_X}, {Vaddr: 0x2000, Length: 0x2000, Flags: elf.PF_X}, }}, @@ -67,7 +67,7 @@ func TestSynchronizeMappings(t *testing.T) { prefixesByG: make(map[libpf.Address][]lpm.Prefix), } for _, call := range tc.calls { - err := lj.synchronizeMappings(ebpf, 0, []process.Mapping{call}) + err := lj.synchronizeMappings(ebpf, 0, []process.RawMapping{call}) require.NoError(t, err) } initial := tc.calls[0] diff --git a/interpreter/multi.go b/interpreter/multi.go index 08634384b..d976228d2 100644 --- a/interpreter/multi.go +++ b/interpreter/multi.go @@ -92,7 +92,7 @@ func (m *MultiInstance) Detach(ebpf EbpfHandler, pid libpf.PID) error { // SynchronizeMappings synchronizes mappings for all interpreter instances. func (m *MultiInstance) SynchronizeMappings(ebpf EbpfHandler, - exeReporter reporter.ExecutableReporter, pr process.Process, mappings []process.Mapping, + exeReporter reporter.ExecutableReporter, pr process.Process, mappings []process.RawMapping, ) error { var errs []error for _, instance := range m.instances { diff --git a/interpreter/nodev8/v8.go b/interpreter/nodev8/v8.go index f153009e2..3fe71a695 100644 --- a/interpreter/nodev8/v8.go +++ b/interpreter/nodev8/v8.go @@ -527,8 +527,8 @@ type v8Instance struct { // pid is the process ID, used to access files via /proc/PID/root/ for containerized processes pid libpf.PID - // mappings is indexed by the Mapping to its generation - mappings map[process.Mapping]*uint32 + // mappings is indexed by the RawMapping to its generation + mappings map[process.RawMapping]*uint32 // prefixes is indexed by the prefix added to ebpf maps (to be cleaned up) to its generation prefixes map[lpm.Prefix]*uint32 // mappingGeneration is the current generation (so old entries can be pruned) @@ -582,7 +582,7 @@ func (i *v8Instance) Detach(ebpf interpreter.EbpfHandler, pid libpf.PID) error { } func (i *v8Instance) SynchronizeMappings(ebpf interpreter.EbpfHandler, - _ reporter.ExecutableReporter, pr process.Process, mappings []process.Mapping, + _ reporter.ExecutableReporter, pr process.Process, mappings []process.RawMapping, ) error { i.pid = pr.PID() i.mappingGeneration++ @@ -1932,7 +1932,7 @@ func (d *v8Data) Attach(ebpf interpreter.EbpfHandler, pid libpf.PID, _ libpf.Add return &v8Instance{ d: d, rm: rm, - mappings: make(map[process.Mapping]*uint32), + mappings: make(map[process.RawMapping]*uint32), prefixes: make(map[lpm.Prefix]*uint32), addrToString: addrToString, addrToCode: addrToCode, diff --git a/interpreter/php/opcache.go b/interpreter/php/opcache.go index 380e05120..2e8f5afdb 100644 --- a/interpreter/php/opcache.go +++ b/interpreter/php/opcache.go @@ -193,7 +193,7 @@ func (i *opcacheInstance) Detach(ebpf interpreter.EbpfHandler, pid libpf.PID) er } func (i *opcacheInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler, - _ reporter.ExecutableReporter, pr process.Process, _ []process.Mapping, + _ reporter.ExecutableReporter, pr process.Process, _ []process.RawMapping, ) error { if i.prefixes != nil { // Already attached diff --git a/interpreter/types.go b/interpreter/types.go index 8c796ca6f..1f69aaa2d 100644 --- a/interpreter/types.go +++ b/interpreter/types.go @@ -175,11 +175,21 @@ type Instance interface { // simple interpreters can use the global Data also as the Instance implementation. Detach(ebpf EbpfHandler, pid libpf.PID) error - // SynchronizeMappings is called when the processmanager has reread process memory - // mappings. Interpreters not needing to process these events can simply ignore them - // by just returning a nil. + // SynchronizeMappings is called when the processmanager has reread process + // memory mappings. The mappings slice contains only the subset of mappings + // that are relevant to interpreters: executable anonymous mappings (for JIT + // engines like HotSpot, V8, BEAM) and DLL file-backed mappings (for .NET + // PE assemblies). The processmanager decides which mappings are included; + // this can be made more dynamic in the future if needed. + // + // The mappings are in /proc/PID/maps order (ascending by virtual address) + // but are NOT sorted by any other criteria. Interpreters that need a + // specific ordering must sort locally. + // + // Interpreters not needing to process these events can simply ignore them + // by returning nil. SynchronizeMappings(ebpf EbpfHandler, exeReporter reporter.ExecutableReporter, - pr process.Process, mappings []process.Mapping) error + pr process.Process, mappings []process.RawMapping) error // UpdateLibcInfo is called when the process C-library related // introspection data has been updated. diff --git a/libc/libc.go b/libc/libc.go index 25343cb6a..576cde5a6 100644 --- a/libc/libc.go +++ b/libc/libc.go @@ -66,20 +66,24 @@ func IsPotentialLibcDSO(filename string) bool { } func ExtractLibcInfo(ef *pfelf.File) (*LibcInfo, error) { - tsdinfo, err := extractTSDInfo(ef) - if err != nil { - return nil, err + info := &LibcInfo{} + + tsdinfo, tsdErr := extractTSDInfo(ef) + if tsdErr == nil { + info.TSDInfo = tsdinfo } - dtvinfo, err := extractDTVInfo(ef) - if err != nil { - return &LibcInfo{}, err + dtvinfo, dtvErr := extractDTVInfo(ef) + if dtvErr == nil { + info.DTVInfo = dtvinfo } - return &LibcInfo{ - TSDInfo: tsdinfo, - DTVInfo: dtvinfo, - }, nil + // Return an error only if both extractions failed. + if tsdErr != nil && dtvErr != nil { + return nil, fmt.Errorf("TSD: %s; DTV: %s", tsdErr, dtvErr) + } + + return info, nil } // This code analyzes the C-library provided POSIX defined function which is used diff --git a/libc/libc_aarch64.go b/libc/libc_aarch64.go index d389694d8..b97eb23e1 100644 --- a/libc/libc_aarch64.go +++ b/libc/libc_aarch64.go @@ -408,6 +408,5 @@ func extractDTVInfoARM(code []byte) (DTVInfo, error) { return DTVInfo{ Offset: dtvOffset, Multiplier: uint8(entryWidth), - Indirect: 1, }, nil } diff --git a/libc/libc_test.go b/libc/libc_test.go index 24b5b81af..4a827380a 100644 --- a/libc/libc_test.go +++ b/libc/libc_test.go @@ -4,10 +4,15 @@ package libc // import "go.opentelemetry.io/ebpf-profiler/libc" import ( + "bytes" "debug/elf" + "encoding/binary" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" ) func TestExtractTSDInfo(t *testing.T) { @@ -313,7 +318,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: 8, Multiplier: 16, - Indirect: 0, }, }, "glibc 2.32 / Fedora 33 / x86_64": { @@ -361,7 +365,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: 8, Multiplier: 16, - Indirect: 0, }, }, "musl 1.2.5 / alpine 3.22.2 / x86_64": { @@ -383,7 +386,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: 8, Multiplier: 8, - Indirect: 1, }, }, "musl 1.1.5 / alpine 3.1 / x86_64": { @@ -411,7 +413,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: 8, Multiplier: 8, - Indirect: 1, }, }, "glibc 2.39 / ubuntu 24.04 / aarch64": { @@ -447,7 +448,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: 0, Multiplier: 16, - Indirect: 1, }, }, "glibc / Fedora 39 / aarch64": { @@ -486,7 +486,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: 0, Multiplier: 16, - Indirect: 1, }, }, "glibc / Fedora 33 / aarch64": { @@ -515,7 +514,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: 0, Multiplier: 16, - Indirect: 1, }, }, @@ -532,7 +530,6 @@ func TestExtractDTVOffset(t *testing.T) { info: DTVInfo{ Offset: -8, Multiplier: 8, - Indirect: 1, }, }, } @@ -554,6 +551,241 @@ func TestExtractDTVOffset(t *testing.T) { } } +// buildTestELF creates a minimal 64-bit ELF binary with the given dynamic symbols. +// Each symbol maps to its corresponding code byte slice. The resulting ELF has a +// SysV hash table so pfelf.File can resolve symbols via LookupSymbol/SymbolData. +func buildTestELF(t *testing.T, machine elf.Machine, symbols map[string][]byte) *pfelf.File { + t.Helper() + + // Layout: ELF header | Phdr[0] PT_LOAD | Phdr[1] PT_DYNAMIC | + // strtab | symtab | hash | dyntab | code... + // + // Everything lives in one PT_LOAD segment starting at vaddr 0. + const vaddr = uint64(0x1000) + + // Build string table: \0 then each symbol name \0-terminated + var strtab bytes.Buffer + strtab.WriteByte(0) // index 0 = empty string + nameOffsets := make(map[string]uint32) + for name := range symbols { + nameOffsets[name] = uint32(strtab.Len()) + strtab.WriteString(name) + strtab.WriteByte(0) + } + + // Build symbol table: Sym64[0] is always null, then one per symbol + numSyms := 1 + len(symbols) + symtab := make([]elf.Sym64, numSyms) + // Symbol index 0 is reserved (STN_UNDEF) + + // We'll fill in addresses after we know the code layout + symOrder := make([]string, 0, len(symbols)) + for name := range symbols { + symOrder = append(symOrder, name) + } + + // sysvHash computes the ELF SysV hash for a symbol name. + sysvHash := func(s string) uint32 { + h := uint32(0) + for _, c := range []byte(s) { + h = 16*h + uint32(c) + h ^= h >> 24 & 0xf0 + } + return h & 0xfffffff + } + + // Build SysV hash table + // nbucket = numSyms, nchain = numSyms (simple 1:1 mapping) + nbucket := uint32(numSyms) + nchain := uint32(numSyms) + + // Now compute sizes for layout + ehdrSize := int(binary.Size(elf.Header64{})) + phdrSize := int(binary.Size(elf.Prog64{})) + numPhdrs := 2 + + strtabOff := ehdrSize + phdrSize*numPhdrs + symtabOff := strtabOff + strtab.Len() + hashOff := symtabOff + numSyms*int(binary.Size(elf.Sym64{})) + hashSize := int(4 + 4 + 4*int(nbucket) + 4*int(nchain)) // nbucket, nchain, buckets, chains + dynOff := hashOff + hashSize + dynSize := int(4 * binary.Size(elf.Dyn64{})) // STRTAB, SYMTAB, HASH, NULL + codeOff := dynOff + dynSize + + // Place code for each symbol + codeOffsets := make(map[string]int) + offset := codeOff + for _, name := range symOrder { + codeOffsets[name] = offset + offset += len(symbols[name]) + } + totalSize := offset + + // Fill in symbol table entries + for i, name := range symOrder { + idx := i + 1 // skip null symbol at index 0 + symtab[idx] = elf.Sym64{ + Name: nameOffsets[name], + Info: byte(elf.STB_GLOBAL)<<4 | byte(elf.STT_FUNC), + Other: byte(elf.STV_DEFAULT), + Shndx: 1, // non-zero = defined + Value: vaddr + uint64(codeOffsets[name]), + Size: uint64(len(symbols[name])), + } + } + + // Build SysV hash: simple bucket[hash % nbucket] = sym_index, chain = 0 + hashBuf := make([]byte, hashSize) + binary.LittleEndian.PutUint32(hashBuf[0:], nbucket) + binary.LittleEndian.PutUint32(hashBuf[4:], nchain) + bucketsStart := 8 + chainsStart := bucketsStart + 4*int(nbucket) + + // Initialize all buckets and chains to 0 (STN_UNDEF) + for i, name := range symOrder { + symIdx := uint32(i + 1) + h := sysvHash(name) + bucket := h % nbucket + bucketOff := bucketsStart + 4*int(bucket) + existing := binary.LittleEndian.Uint32(hashBuf[bucketOff:]) + if existing == 0 { + binary.LittleEndian.PutUint32(hashBuf[bucketOff:], symIdx) + } else { + // Chain from existing + cur := existing + for { + chainOff := chainsStart + 4*int(cur) + next := binary.LittleEndian.Uint32(hashBuf[chainOff:]) + if next == 0 { + binary.LittleEndian.PutUint32(hashBuf[chainOff:], symIdx) + break + } + cur = next + } + } + } + + // Build dynamic table + dynEntries := []elf.Dyn64{ + {Tag: int64(elf.DT_STRTAB), Val: vaddr + uint64(strtabOff)}, + {Tag: int64(elf.DT_SYMTAB), Val: vaddr + uint64(symtabOff)}, + {Tag: int64(elf.DT_HASH), Val: vaddr + uint64(hashOff)}, + {Tag: int64(elf.DT_NULL), Val: 0}, + } + + // Assemble the ELF + buf := make([]byte, totalSize) + + // ELF header + hdr := elf.Header64{ + Ident: [16]byte{0x7f, 'E', 'L', 'F', byte(elf.ELFCLASS64), byte(elf.ELFDATA2LSB), byte(elf.EV_CURRENT)}, + Type: uint16(elf.ET_DYN), + Machine: uint16(machine), + Version: uint32(elf.EV_CURRENT), + Entry: vaddr + uint64(codeOff), + Phoff: uint64(ehdrSize), + Ehsize: uint16(ehdrSize), + Phentsize: uint16(phdrSize), + Phnum: uint16(numPhdrs), + } + binary.Encode(buf[0:], binary.LittleEndian, &hdr) + + // Program headers + phLoad := elf.Prog64{ + Type: uint32(elf.PT_LOAD), + Flags: uint32(elf.PF_R | elf.PF_X), + Off: 0, + Vaddr: vaddr, + Paddr: vaddr, + Filesz: uint64(totalSize), + Memsz: uint64(totalSize), + Align: 0x1000, + } + binary.Encode(buf[ehdrSize:], binary.LittleEndian, &phLoad) + + phDyn := elf.Prog64{ + Type: uint32(elf.PT_DYNAMIC), + Flags: uint32(elf.PF_R), + Off: uint64(dynOff), + Vaddr: vaddr + uint64(dynOff), + Paddr: vaddr + uint64(dynOff), + Filesz: uint64(dynSize), + Memsz: uint64(dynSize), + Align: 8, + } + binary.Encode(buf[ehdrSize+phdrSize:], binary.LittleEndian, &phDyn) + + // String table + copy(buf[strtabOff:], strtab.Bytes()) + + // Symbol table + for i, sym := range symtab { + binary.Encode(buf[symtabOff+i*int(binary.Size(elf.Sym64{})):], binary.LittleEndian, &sym) + } + + // Hash table + copy(buf[hashOff:], hashBuf) + + // Dynamic table + for i, dyn := range dynEntries { + binary.Encode(buf[dynOff+i*int(binary.Size(elf.Dyn64{})):], binary.LittleEndian, &dyn) + } + + // Code sections + for _, name := range symOrder { + copy(buf[codeOffsets[name]:], symbols[name]) + } + + ef, err := pfelf.NewFile(bytes.NewReader(buf), 0, false) + require.NoError(t, err) + return ef +} + +// TestExtractLibcInfoIndependence verifies that TSD and DTV extraction are +// independent: failure to extract one should not prevent extraction of the other. +// This is a regression test for a bug where ExtractLibcInfo would bail out +// entirely if extractTSDInfo failed, even when __tls_get_addr was available +// (e.g., in ld-linux.so which exports __tls_get_addr but not pthread_getspecific). +func TestExtractLibcInfoIndependence(t *testing.T) { + // glibc 2.36 / debian 12 / x86_64 __tls_get_addr machine code + tlsGetAddrCode := []byte{ + 0x64, 0x48, 0x8b, 0x14, 0x25, 0x08, 0x00, 0x00, 0x00, + 0x48, 0x8b, 0x05, 0x48, 0xfc, 0x01, 0x00, + 0x48, 0x39, 0x02, + 0x75, 0x16, + 0x48, 0x8b, 0x07, + 0x48, 0xc1, 0xe0, 0x04, + 0x48, 0x8b, 0x04, 0x02, + 0x48, 0x83, 0xf8, 0xff, + 0x74, 0x05, + 0x48, 0x03, 0x47, 0x08, + 0xc3, + } + + // Build a minimal ELF with ONLY __tls_get_addr (no pthread_getspecific). + // This simulates ld-linux.so which exports __tls_get_addr but not the + // pthread_getspecific symbol. + ef := buildTestELF(t, elf.EM_X86_64, map[string][]byte{ + "__tls_get_addr": tlsGetAddrCode, + }) + + // Call ExtractLibcInfo — previously this would return (nil, err) because + // extractTSDInfo failed first and short-circuited the DTV extraction. + info, err := ExtractLibcInfo(ef) + + // Should succeed (no error) because DTV extraction works even though TSD fails. + assert.NoError(t, err) + require.NotNil(t, info, "ExtractLibcInfo should return non-nil LibcInfo") + + // TSD should be empty (no pthread_getspecific symbol) + assert.False(t, info.HasTSDInfo(), "should not have TSD info") + + // DTV should be populated from __tls_get_addr + assert.True(t, info.HasDTVInfo(), "should have DTV info from __tls_get_addr") + assert.Equal(t, int16(8), info.DTVInfo.Offset) + assert.Equal(t, uint8(16), info.DTVInfo.Multiplier) +} + func TestLibcInfoIsEqual(t *testing.T) { testCases := map[string]struct { left LibcInfo @@ -575,7 +807,6 @@ func TestLibcInfoIsEqual(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, right: LibcInfo{ @@ -587,7 +818,6 @@ func TestLibcInfoIsEqual(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, expectEqual: true, @@ -598,7 +828,6 @@ func TestLibcInfoIsEqual(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, right: LibcInfo{ @@ -652,7 +881,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, expected: LibcInfo{ @@ -660,7 +888,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, }, @@ -670,7 +897,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, right: LibcInfo{ @@ -690,7 +916,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, }, @@ -708,7 +933,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, expected: LibcInfo{ @@ -720,7 +944,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, }, @@ -737,7 +960,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, right: LibcInfo{ @@ -749,7 +971,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: 8, Multiplier: 16, - Indirect: 1, }, }, expected: LibcInfo{ @@ -761,7 +982,6 @@ func TestLibcInfoMerge(t *testing.T) { DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 0, }, }, }, diff --git a/libc/libc_x86.go b/libc/libc_x86.go index 7df5cb792..8778958a0 100644 --- a/libc/libc_x86.go +++ b/libc/libc_x86.go @@ -107,7 +107,9 @@ func extractDTVInfoX86(code []byte) (DTVInfo, error) { entryWidth = e.NewImmediateCapture("entryWidth") ) - // Pattern 1: glibc - Direct DTV access + // Pattern 1: glibc - DTV pointer loaded from FS:offset, then indexed + // FS:offset is a memory load that retrieves the DTV pointer, so this is + // indirect access (two dereferences: load DTV ptr, then index into DTV). expected := e.Add( e.Mem8( e.Add( @@ -122,7 +124,6 @@ func extractDTVInfoX86(code []byte) (DTVInfo, error) { return DTVInfo{ Offset: int16(dtvOffset.CapturedValue() & 0xFFFF), Multiplier: uint8(entryWidth.CapturedValue()), - Indirect: 0, }, nil } @@ -145,7 +146,6 @@ func extractDTVInfoX86(code []byte) (DTVInfo, error) { return DTVInfo{ Offset: int16(dtvOffset.CapturedValue() & 0xFFFF), Multiplier: uint8(entryWidth.CapturedValue()), - Indirect: 1, }, nil } @@ -164,7 +164,6 @@ func extractDTVInfoX86(code []byte) (DTVInfo, error) { return DTVInfo{ Offset: int16(dtvOffset.CapturedValue() & 0xFFFF), Multiplier: uint8(entryWidth.CapturedValue()), - Indirect: 1, }, nil } @@ -184,7 +183,6 @@ func extractDTVInfoX86(code []byte) (DTVInfo, error) { return DTVInfo{ Offset: int16(dtvOffset.CapturedValue() & 0xFFFF), Multiplier: uint8(entryWidth.CapturedValue()), - Indirect: 1, }, nil } diff --git a/libpf/apm.go b/libpf/apm.go index 903316b05..530c6ab3a 100644 --- a/libpf/apm.go +++ b/libpf/apm.go @@ -8,3 +8,4 @@ type APMTraceID [16]byte type APMTransactionID = APMSpanID var InvalidAPMSpanID = APMSpanID{0, 0, 0, 0, 0, 0, 0, 0} +var InvalidAPMTraceID = APMTraceID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} diff --git a/metrics/metrics.go b/metrics/metrics.go index a52633dd2..05ee9abef 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -60,7 +60,7 @@ func Start(meter metric.Meter) { defs := GetDefinitions() metricTypes = make(map[MetricID]MetricType, len(defs)) for _, md := range defs { - if md.Obsolete { + if md.Obsolete || md.Field == "" { continue } metricTypes[md.ID] = md.Type diff --git a/process/coredump.go b/process/coredump.go index 385ce52d2..053fa7ccb 100644 --- a/process/coredump.go +++ b/process/coredump.go @@ -46,7 +46,7 @@ type CoredumpProcess struct { machineData MachineData // mappings contains the parsed mappings. - mappings []Mapping + mappings []RawMapping // threadInfo contains the parsed thread info. threadInfo []ThreadInfo @@ -145,7 +145,7 @@ func OpenCoredumpFile(f *pfelf.File) (*CoredumpProcess, error) { cd := &CoredumpProcess{ File: f, files: make(map[string]*CoredumpFile), - mappings: make([]Mapping, 0, len(f.Progs)), + mappings: make([]RawMapping, 0, len(f.Progs)), threadInfo: make([]ThreadInfo, 0, 8), } cd.machineData.Machine = cd.Machine @@ -157,7 +157,7 @@ func OpenCoredumpFile(f *pfelf.File) (*CoredumpProcess, error) { for i := range f.Progs { p := &f.Progs[i] if p.Type == elf.PT_LOAD && p.Flags != 0 { - m := Mapping{ + m := RawMapping{ Vaddr: p.Vaddr, Length: p.Memsz, Flags: p.Flags, @@ -269,9 +269,14 @@ func (cd *CoredumpProcess) GetExe() (libpf.String, error) { return cd.fname, nil } -// GetMappings implements the Process interface. -func (cd *CoredumpProcess) GetMappings() ([]Mapping, uint32, error) { - return cd.mappings, 0, nil +// IterateMappings implements the Process interface. +func (cd *CoredumpProcess) IterateMappings(callback func(m RawMapping) bool) (uint32, error) { + for _, m := range cd.mappings { + if !callback(m) { + return 0, ErrCallbackStopped + } + } + return 0, nil } // GetThreadInfo implements the Process interface. @@ -280,18 +285,18 @@ func (cd *CoredumpProcess) GetThreads() ([]ThreadInfo, error) { } // OpenMappingFile implements the Process interface. -func (cd *CoredumpProcess) OpenMappingFile(_ *Mapping) (ReadAtCloser, error) { +func (cd *CoredumpProcess) OpenMappingFile(_ *RawMapping) (ReadAtCloser, error) { // Coredumps do not contain the original backing files. return nil, errors.New("coredump does not support opening backing file") } // GetMappingFileLastModified implements the Process interface. -func (cd *CoredumpProcess) GetMappingFileLastModified(_ *Mapping) int64 { +func (cd *CoredumpProcess) GetMappingFileLastModified(_ *RawMapping) int64 { return 0 } // CalculateMappingFileID implements the Process interface. -func (cd *CoredumpProcess) CalculateMappingFileID(m *Mapping) (libpf.FileID, error) { +func (cd *CoredumpProcess) CalculateMappingFileID(m *RawMapping) (libpf.FileID, error) { // It is not possible to calculate the real FileID as the section headers // are likely missing. So just return a synthesized FileID. vaddr := make([]byte, 8) @@ -299,7 +304,7 @@ func (cd *CoredumpProcess) CalculateMappingFileID(m *Mapping) (libpf.FileID, err h := fnv.New128a() _, _ = h.Write(vaddr) - _, _ = h.Write([]byte(m.Path.String())) + _, _ = h.Write([]byte(m.Path)) return libpf.FileIDFromBytes(h.Sum(nil)) } @@ -399,7 +404,7 @@ func (cd *CoredumpProcess) parseMappings(desc []byte, cf.Mappings = append(cf.Mappings, cm) mapping := &cd.mappings[m.mappingIndex] - mapping.Path = cf.Name + mapping.Path = cf.Name.String() mapping.FileOffset = entry.FileOffset * hdr.PageSize // Synthesize non-zero device and inode indicating this is a filebacked mapping. mapping.Device = 1 @@ -408,14 +413,14 @@ func (cd *CoredumpProcess) parseMappings(desc []byte, // This file backed mapping is not in the coredump LOAD tables // Likely a executable mapping excluded by core_filter. Construct // the mappings assuming R+X. - cd.mappings = append(cd.mappings, Mapping{ + cd.mappings = append(cd.mappings, RawMapping{ Vaddr: entry.Start, Length: entry.End - entry.Start, Flags: elf.PF_R + elf.PF_X, FileOffset: entry.FileOffset * hdr.PageSize, Device: 1, Inode: cf.inode, - Path: cf.Name, + Path: cf.Name.String(), }) } strs = strs[fnlen+1:] @@ -438,7 +443,7 @@ func (cd *CoredumpProcess) parseAuxVector(desc []byte, vaddrToMappings map[uint6 vm.Inode = vdsoInode vm.Path = VdsoPathName - cf := cd.getFile(vm.Path.String()) + cf := cd.getFile(vm.Path) cm := CoredumpMapping{ Prog: m.prog, File: cf, diff --git a/process/process.go b/process/process.go index 6901a95e3..46e341945 100644 --- a/process/process.go +++ b/process/process.go @@ -27,9 +27,13 @@ import ( "go.opentelemetry.io/ebpf-profiler/stringutil" ) -// GetMappings returns this error when no mappings can be extracted. +// ErrNoMappings is returned when no mappings can be extracted. var ErrNoMappings = errors.New("no mappings") +// ErrCallbackStopped is returned when the IterateMappings callback returns +// false, signaling that iteration was intentionally interrupted. +var ErrCallbackStopped = errors.New("IterateMappings stopped by callback") + const ( containerSource = "[0-9a-f]{64}" taskSource = "[0-9a-f]{32}-\\d+" @@ -55,7 +59,7 @@ type systemProcess struct { mainThreadExit bool remoteMemory remotememory.RemoteMemory - fileToMapping map[string]*Mapping + fileToMapping map[string]*RawMapping } var _ Process = &systemProcess{} @@ -189,13 +193,12 @@ func trimMappingPath(path string) string { return path } -func parseMappings(mapsFile io.Reader) ([]Mapping, uint32, error) { +func iterateMappings(mapsFile io.Reader, callback func(m RawMapping) bool) (uint32, error) { numParseErrors := uint32(0) - mappings := make([]Mapping, 0, 32) scanner := bufio.NewScanner(mapsFile) scanBuf := bufPool.Get().(*[]byte) if scanBuf == nil { - return mappings, 0, errors.New("failed to get memory from sync pool") + return 0, errors.New("failed to get memory from sync pool") } defer func() { // Reset memory and return it for reuse. @@ -211,6 +214,10 @@ func parseMappings(mapsFile io.Reader) ([]Mapping, uint32, error) { var addrs [2]string var devs [2]string + // WARNING: line (and all substrings derived from it, including the + // Path field of the emitted RawMapping) points into scanBuf which is + // recycled after iteration. Callers must intern Path (libpf.Intern) + // before storing. line := pfunsafe.ToString(scanner.Bytes()) if stringutil.FieldsN(line, fields[:]) < 5 { numParseErrors++ @@ -266,7 +273,7 @@ func parseMappings(mapsFile io.Reader) ([]Mapping, uint32, error) { } device := major<<8 + minor - var path libpf.String + var path string if inode == 0 { if fields[5] == "[vdso]" { // Map to something filename looking with synthesized inode @@ -280,7 +287,7 @@ func parseMappings(mapsFile io.Reader) ([]Mapping, uint32, error) { continue } } else { - path = libpf.Intern(trimMappingPath(fields[5])) + path = trimMappingPath(fields[5]) } vaddr, err := strconv.ParseUint(addrs[0], 16, 64) @@ -304,7 +311,7 @@ func parseMappings(mapsFile io.Reader) ([]Mapping, uint32, error) { continue } - mappings = append(mappings, Mapping{ + if !callback(RawMapping{ Vaddr: vaddr, Length: length, Flags: flags, @@ -312,29 +319,39 @@ func parseMappings(mapsFile io.Reader) ([]Mapping, uint32, error) { Device: device, Inode: inode, Path: path, - }) + }) { + return numParseErrors, ErrCallbackStopped + } } - return mappings, numParseErrors, scanner.Err() + return numParseErrors, scanner.Err() } -// GetMappings will process the mappings file from proc. Additionally, -// a reverse map from mapping filename to a Mapping node is built to allow -// OpenELF opening ELF files using the corresponding proc map_files entry. -// WARNING: This implementation does not support calling GetMappings -// concurrently with itself, or with OpenELF. -func (sp *systemProcess) GetMappings() ([]Mapping, uint32, error) { +func (sp *systemProcess) IterateMappings(callback func(m RawMapping) bool) (uint32, error) { mapsFile, err := os.Open(fmt.Sprintf("/proc/%d/maps", sp.pid)) if err != nil { - return nil, 0, err + return 0, err } defer mapsFile.Close() - mappings, numParseErrors, err := parseMappings(mapsFile) + fileToMapping := make(map[string]*RawMapping) + gotMappings := false + + collectForOpenELF := func(m RawMapping) bool { + gotMappings = true + if m.IsExecutable() || m.IsVDSO() { + stored := m + stored.Path = libpf.Intern(m.Path).String() + fileToMapping[stored.Path] = &stored + } + return callback(m) + } + + numParseErrors, err := iterateMappings(mapsFile, collectForOpenELF) if err != nil { - return mappings, numParseErrors, err + return numParseErrors, err } - if len(mappings) == 0 { + if !gotMappings { // We could test for main thread exit here by checking for zombie state // in /proc/sp.pid/stat but it's simpler to assume that this is the case // and try extracting mappings for a different thread. Since we stopped @@ -344,7 +361,7 @@ func (sp *systemProcess) GetMappings() ([]Mapping, uint32, error) { sp.mainThreadExit = true if sp.pid == sp.tid { - return mappings, numParseErrors, ErrNoMappings + return numParseErrors, ErrNoMappings } log.Debugf("TID: %v extracting mappings", sp.tid) @@ -356,24 +373,17 @@ func (sp *systemProcess) GetMappings() ([]Mapping, uint32, error) { // the agent to unload process metadata when a thread exits but the process is still // alive). if err != nil { - return mappings, numParseErrors, ErrNoMappings + return numParseErrors, ErrNoMappings } defer mapsFileAlt.Close() - mappings, numParseErrors, err = parseMappings(mapsFileAlt) - if err != nil || len(mappings) == 0 { - return mappings, numParseErrors, ErrNoMappings + numParseErrors, err := iterateMappings(mapsFileAlt, collectForOpenELF) + if err != nil || !gotMappings { + return numParseErrors, ErrNoMappings } } - fileToMapping := make(map[string]*Mapping) - for idx := range mappings { - m := &mappings[idx] - if m.Path != libpf.NullString { - fileToMapping[m.Path.String()] = m - } - } sp.fileToMapping = fileToMapping - return mappings, numParseErrors, nil + return numParseErrors, nil } func (sp *systemProcess) GetThreads() ([]ThreadInfo, error) { @@ -388,7 +398,7 @@ func (sp *systemProcess) GetRemoteMemory() remotememory.RemoteMemory { return sp.remoteMemory } -func (sp *systemProcess) extractMapping(m *Mapping) (*bytes.Reader, error) { +func (sp *systemProcess) extractMapping(m *RawMapping) (*bytes.Reader, error) { data := make([]byte, m.Length) _, err := sp.remoteMemory.ReadAt(data, int64(m.Vaddr)) if err != nil { @@ -398,8 +408,8 @@ func (sp *systemProcess) extractMapping(m *Mapping) (*bytes.Reader, error) { return bytes.NewReader(data), nil } -func (sp *systemProcess) getMappingFile(m *Mapping) string { - if m.IsAnonymous() || m.IsVDSO() { +func (sp *systemProcess) getMappingFile(m *RawMapping) string { + if !m.IsFileBacked() { return "" } if sp.mainThreadExit { @@ -407,12 +417,12 @@ func (sp *systemProcess) getMappingFile(m *Mapping) string { // nor /proc/sp.pid/root exist if main thread has exited, so we use the // mapping path directly under the sp.tid root. rootPath := fmt.Sprintf("/proc/%v/task/%v/root", sp.pid, sp.tid) - return path.Join(rootPath, m.Path.String()) + return path.Join(rootPath, m.Path) } return fmt.Sprintf("/proc/%v/map_files/%x-%x", sp.pid, m.Vaddr, m.Vaddr+m.Length) } -func (sp *systemProcess) OpenMappingFile(m *Mapping) (ReadAtCloser, error) { +func (sp *systemProcess) OpenMappingFile(m *RawMapping) (ReadAtCloser, error) { filename := sp.getMappingFile(m) if filename == "" { return nil, errors.New("no backing file for anonymous memory") @@ -420,7 +430,7 @@ func (sp *systemProcess) OpenMappingFile(m *Mapping) (ReadAtCloser, error) { return os.Open(filename) } -func (sp *systemProcess) GetMappingFileLastModified(m *Mapping) int64 { +func (sp *systemProcess) GetMappingFileLastModified(m *RawMapping) int64 { filename := sp.getMappingFile(m) if filename != "" { var st unix.Stat_t @@ -435,7 +445,7 @@ func (sp *systemProcess) GetMappingFileLastModified(m *Mapping) int64 { // VDSO for the system. var vdsoFileID libpf.FileID -func (sp *systemProcess) CalculateMappingFileID(m *Mapping) (libpf.FileID, error) { +func (sp *systemProcess) CalculateMappingFileID(m *RawMapping) (libpf.FileID, error) { if m.IsVDSO() { if vdsoFileID != (libpf.FileID{}) { return vdsoFileID, nil diff --git a/process/process_test.go b/process/process_test.go index b7c943c9e..e67ac2593 100644 --- a/process/process_test.go +++ b/process/process_test.go @@ -5,6 +5,7 @@ package process import ( "debug/elf" + "io" "os" "runtime" "strings" @@ -30,87 +31,135 @@ var testMappings = `55fe82710000-55fe8273c000 r--p 00000000 fd:01 1068432 7f63c8eef000 r-xp 0001c000 1fd:01 1075944 7f8b929f0000-7f8b92a00000 r-xp 00000000 00:00 0 ` +var allExpectedMappings = []RawMapping{ + { + Vaddr: 0x55fe82710000, + Device: 0xfd01, + Flags: elf.PF_R, + Inode: 1068432, + Length: 0x2c000, + FileOffset: 0, + Path: "/tmp/usr_bin_seahorse", + }, + { + Vaddr: 0x55fe8273c000, + Device: 0xfd01, + Flags: elf.PF_R + elf.PF_X, + Inode: 1068432, + Length: 0x82000, + FileOffset: 0x2c000, + Path: "/tmp/usr_bin_seahorse", + }, + { + Vaddr: 0x55fe827be000, + Device: 0xfd01, + Flags: elf.PF_R, + Inode: 1068432, + Length: 0x78000, + FileOffset: 0xae000, + Path: "/tmp/usr_bin_seahorse", + }, + { + Vaddr: 0x55fe82836000, + Device: 0xfd01, + Flags: elf.PF_R, + Inode: 1068432, + Length: 0x7000, + FileOffset: 0x125000, + Path: "/tmp/usr_bin_seahorse", + }, + { + Vaddr: 0x55fe8283d000, + Device: 0xfd01, + Flags: elf.PF_R + elf.PF_W, + Inode: 1068432, + Length: 0x1000, + FileOffset: 0x12c000, + Path: "/tmp/usr_bin_seahorse", + }, + { + Vaddr: 0x7f63c8c3e000, + Device: 0x0801, + Flags: elf.PF_R + elf.PF_X, + Inode: 1048922, + Length: 0x1A2000, + FileOffset: 544768, + Path: "/tmp/usr_lib_x86_64-linux-gnu_libcrypto.so.1.1", + }, + { + Vaddr: 0x7f63c8ebf000, + Device: 0x1fd01, + Flags: elf.PF_R + elf.PF_X, + Inode: 1075944, + Length: 0x130000, + FileOffset: 114688, + Path: "/tmp/usr_lib_x86_64-linux-gnu_libopensc.so.6.0.0", + }, + { + Vaddr: 0x7f8b929f0000, + Device: 0x0, + Flags: elf.PF_R + elf.PF_X, + Inode: 0, + Length: 0x10000, + FileOffset: 0, + Path: "", + }, +} + +func getTestMappings(t *testing.T, mapsFile io.Reader) ([]RawMapping, uint32, error) { + t.Helper() + + mappings := make([]RawMapping, 0, 32) + numParseErrors, err := iterateMappings(mapsFile, func(m RawMapping) bool { + m.Path = libpf.Intern(m.Path).String() + mappings = append(mappings, m) + return true + }) + return mappings, numParseErrors, err +} + +func getTestMappingsFromProcess(t *testing.T, process Process) ([]RawMapping, uint32, error) { + t.Helper() + + mappings := make([]RawMapping, 0, 32) + numParseErrors, err := process.IterateMappings(func(m RawMapping) bool { + m.Path = libpf.Intern(m.Path).String() + mappings = append(mappings, m) + return true + }) + return mappings, numParseErrors, err +} + func TestParseMappings(t *testing.T) { - mappings, numParseErrors, err := parseMappings(strings.NewReader(testMappings)) + mappings, numParseErrors, err := getTestMappings(t, strings.NewReader(testMappings)) require.NoError(t, err) require.Equal(t, uint32(4), numParseErrors) - assert.NotNil(t, mappings) + assert.Equal(t, allExpectedMappings, mappings) +} - expected := []Mapping{ - { - Vaddr: 0x55fe82710000, - Device: 0xfd01, - Flags: elf.PF_R, - Inode: 1068432, - Length: 0x2c000, - FileOffset: 0, - Path: libpf.Intern("/tmp/usr_bin_seahorse"), - }, - { - Vaddr: 0x55fe8273c000, - Device: 0xfd01, - Flags: elf.PF_R + elf.PF_X, - Inode: 1068432, - Length: 0x82000, - FileOffset: 0x2c000, - Path: libpf.Intern("/tmp/usr_bin_seahorse"), - }, - { - Vaddr: 0x55fe827be000, - Device: 0xfd01, - Flags: elf.PF_R, - Inode: 1068432, - Length: 0x78000, - FileOffset: 0xae000, - Path: libpf.Intern("/tmp/usr_bin_seahorse"), - }, - { - Vaddr: 0x55fe82836000, - Device: 0xfd01, - Flags: elf.PF_R, - Inode: 1068432, - Length: 0x7000, - FileOffset: 0x125000, - Path: libpf.Intern("/tmp/usr_bin_seahorse"), - }, - { - Vaddr: 0x55fe8283d000, - Device: 0xfd01, - Flags: elf.PF_R + elf.PF_W, - Inode: 1068432, - Length: 0x1000, - FileOffset: 0x12c000, - Path: libpf.Intern("/tmp/usr_bin_seahorse"), - }, - { - Vaddr: 0x7f63c8c3e000, - Device: 0x0801, - Flags: elf.PF_R + elf.PF_X, - Inode: 1048922, - Length: 0x1A2000, - FileOffset: 544768, - Path: libpf.Intern("/tmp/usr_lib_x86_64-linux-gnu_libcrypto.so.1.1"), - }, - { - Vaddr: 0x7f63c8ebf000, - Device: 0x1fd01, - Flags: elf.PF_R + elf.PF_X, - Inode: 1075944, - Length: 0x130000, - FileOffset: 114688, - Path: libpf.Intern("/tmp/usr_lib_x86_64-linux-gnu_libopensc.so.6.0.0"), - }, - { - Vaddr: 0x7f8b929f0000, - Device: 0x0, - Flags: elf.PF_R + elf.PF_X, - Inode: 0, - Length: 0x10000, - FileOffset: 0, - Path: libpf.NullString, - }, +func TestMappingPredicates(t *testing.T) { + tests := []struct { + name string + m RawMapping + wantAnon bool + wantFile bool + wantMemFD bool + wantVDSO bool + }{ + {"anonymous", RawMapping{}, true, false, false, false}, + {"file-backed", RawMapping{Path: "/usr/lib/foo.so"}, false, true, false, false}, + {"memfd", RawMapping{Path: "/memfd:jit"}, true, false, true, false}, + {"vdso", RawMapping{Path: VdsoPathName}, false, false, false, true}, + {"/dev/zero normalized", RawMapping{Inode: 42, Device: 1}, true, false, false, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.wantAnon, tt.m.IsAnonymous(), "IsAnonymous") + assert.Equal(t, tt.wantFile, tt.m.IsFileBacked(), "IsFileBacked") + assert.Equal(t, tt.wantMemFD, tt.m.IsMemFD(), "IsMemFD") + assert.Equal(t, tt.wantVDSO, tt.m.IsVDSO(), "IsVDSO") + }) } - assert.Equal(t, expected, mappings) } func TestNewPIDOfSelf(t *testing.T) { @@ -121,7 +170,7 @@ func TestNewPIDOfSelf(t *testing.T) { pr := New(pid, pid) assert.NotNil(t, pr) - mappings, numParseErrors, err := pr.GetMappings() + mappings, numParseErrors, err := getTestMappingsFromProcess(t, pr) require.NoError(t, err) require.Equal(t, uint32(0), numParseErrors) assert.NotEmpty(t, mappings) diff --git a/process/types.go b/process/types.go index 54efc0dea..f838586e9 100644 --- a/process/types.go +++ b/process/types.go @@ -17,13 +17,19 @@ import ( ) // VdsoPathName is the path to use for VDSO mappings. -var VdsoPathName = libpf.Intern("linux-vdso.1.so") +const VdsoPathName = "linux-vdso.1.so" // vdsoInode is the synthesized inode number for VDSO mappings. const vdsoInode = 50 -// Mapping contains information about a memory mapping. -type Mapping struct { +// RawMapping represents a memory mapping parsed from /proc/pid/maps or a coredump. +// +// WARNING: When produced by the systemProcess IterateMappings implementation, +// Path may reference an internal scanner buffer that is recycled after the +// iteration completes. Callers that need to store the mapping beyond the +// callback scope must intern the Path via libpf.Intern to detach it from the +// buffer and deduplicate identical paths across mappings. +type RawMapping struct { // Vaddr is the virtual memory start for this mapping. Vaddr uint64 // Length is the length of the mapping. @@ -36,27 +42,34 @@ type Mapping struct { Device uint64 // Inode holds the mapped file's inode number. Inode uint64 - // Path contains the file name for file backed mappings. - Path libpf.String + // Path is the file path for file-backed and special mappings. + // When received from IterateMappings, this may point into an internal + // buffer. The caller must use libpf.Intern to detach it before storing + // the mapping long-term. + Path string } -func (m *Mapping) IsExecutable() bool { +func (m *RawMapping) IsExecutable() bool { return m.Flags&elf.PF_X == elf.PF_X } -func (m *Mapping) IsAnonymous() bool { - return m.Path == libpf.NullString || m.IsMemFD() +func (m *RawMapping) IsAnonymous() bool { + return !m.IsFileBacked() && !m.IsVDSO() } -func (m *Mapping) IsMemFD() bool { - return strings.HasPrefix(m.Path.String(), "/memfd:") +func (m *RawMapping) IsFileBacked() bool { + return m.Path != "" && !m.IsVDSO() && !m.IsMemFD() } -func (m *Mapping) IsVDSO() bool { +func (m *RawMapping) IsMemFD() bool { + return strings.HasPrefix(m.Path, "/memfd:") +} + +func (m *RawMapping) IsVDSO() bool { return m.Path == VdsoPathName } -func (m *Mapping) GetOnDiskFileIdentifier() util.OnDiskFileIdentifier { +func (m *RawMapping) GetOnDiskFileIdentifier() util.OnDiskFileIdentifier { return util.OnDiskFileIdentifier{ DeviceID: m.Device, InodeNum: m.Inode, @@ -124,8 +137,13 @@ type Process interface { // GetExe returns the executable path of the process. GetExe() (libpf.String, error) - // GetMappings reads and parses process memory mappings. - GetMappings() ([]Mapping, uint32, error) + // IterateMappings parses process memory mappings and calls the + // callback for each mapping. The RawMapping's Path field may reference + // an internal buffer that is recycled after the iteration completes; + // callers must use libpf.Intern to detach the Path before storing the + // mapping beyond the callback scope. Returning false from the callback + // stops iteration and causes ErrCallbackStopped to be returned. + IterateMappings(callback func(m RawMapping) bool) (uint32, error) // GetThreads reads the process thread states. GetThreads() ([]ThreadInfo, error) @@ -134,14 +152,14 @@ type Process interface { GetRemoteMemory() remotememory.RemoteMemory // OpenMappingFile returns ReadAtCloser accessing the backing file of the mapping. - OpenMappingFile(*Mapping) (ReadAtCloser, error) + OpenMappingFile(*RawMapping) (ReadAtCloser, error) // GetMappingFileLastModifed returns the timestamp when the backing file was last modified // or zero if an error occurs or mapping file is not accessible via filesystem. - GetMappingFileLastModified(*Mapping) int64 + GetMappingFileLastModified(*RawMapping) int64 // CalculateMappingFileID calculates FileID of the backing file. - CalculateMappingFileID(*Mapping) (libpf.FileID, error) + CalculateMappingFileID(*RawMapping) (libpf.FileID, error) io.Closer diff --git a/processmanager/ebpf/ebpf.go b/processmanager/ebpf/ebpf.go index 0a929aad4..78c14cdfb 100644 --- a/processmanager/ebpf/ebpf.go +++ b/processmanager/ebpf/ebpf.go @@ -74,9 +74,9 @@ type ebpfMapsImpl struct { errCounterLock sync.Mutex errCounter map[metrics.MetricID]int64 - hasGenericBatchOperations bool - hasGenericBatchLookupAndDelete bool - hasLPMTrieBatchOperations bool + // Support for batch operations on LPM eBPF maps was only + // introduced with Linux kernel 5.13. + hasLPMTrieBatchOperations bool updateWorkers *asyncMapUpdaterPool @@ -145,16 +145,6 @@ func LoadMaps(ctx context.Context, includeTracers types.IncludedTracers, maps ma impl.ExeIDToStackDeltaMaps[i-support.StackDeltaBucketSmallest] = deltasMap } - if err := probeBatchOperations(cebpf.Hash); err == nil { - log.Infof("Supports generic eBPF map batch operations") - impl.hasGenericBatchOperations = true - } - - if err := probeBatchLookupAndDelete(cebpf.Hash); err == nil { - log.Infof("Supports generic eBPF map batch lookup-and-delete") - impl.hasGenericBatchLookupAndDelete = true - } - if err := probeBatchOperations(cebpf.LPMTrie); err == nil { log.Infof("Supports LPM trie eBPF map batch operations") impl.hasLPMTrieBatchOperations = true @@ -496,7 +486,7 @@ func (impl *ebpfMapsImpl) DeleteProcData(typ libpf.InterpreterType, pid libpf.PI pid32 := uint32(pid) if err := ebpfMap.Delete(unsafe.Pointer(&pid32)); err != nil { - return fmt.Errorf("failed to remove info: %v", err) + return fmt.Errorf("failed to remove info: %w", err) } return nil } @@ -729,6 +719,12 @@ func probeBatchOperations(mapType cebpf.MapType) error { return probeMapOperations(mapType, probeBatchOperationsInner[uint64]) } +// SupportsLPMTrieBatchOperations returns true if the kernel supports eBPF batch operations +// on LPM trie maps. +func (impl *ebpfMapsImpl) SupportsLPMTrieBatchOperations() bool { + return impl.hasLPMTrieBatchOperations +} + // getMapID returns the mapID number to use for given number of stack deltas. func getMapID(numDeltas uint32) (uint16, error) { significantBits := 32 - bits.LeadingZeros32(numDeltas) @@ -818,44 +814,26 @@ func (impl *ebpfMapsImpl) UpdateExeIDToStackDeltas(fileID host.FileID, impl.updateWorkers.EnqueueUpdate(outerMap, fileID, innerMapCloned) - if impl.hasGenericBatchOperations { - innerKeys := make([]uint32, numDeltas) - stackDeltas := make([]support.StackDelta, numDeltas) - - // Prepare values for batch update. - for index, delta := range deltas { - innerKeys[index] = uint32(index) - stackDeltas[index].AddrLow = delta.AddressLow - stackDeltas[index].UnwindInfo = delta.UnwindInfo - } - - _, err := innerMap.BatchUpdate( - ptrCastMarshaler[uint32](innerKeys), - ptrCastMarshaler[support.StackDelta](stackDeltas), - &cebpf.BatchOptions{Flags: uint64(cebpf.UpdateAny)}) - if err != nil { - return 0, impl.trackMapError(metrics.IDExeIDToStackDeltasBatchUpdate, - fmt.Errorf("failed to batch insert %d elements for 0x%x "+ - "into exeIDTostack_deltas: %v", - numDeltas, fileID, err)) - } - return mapID, nil - } + innerKeys := make([]uint32, numDeltas) + stackDeltas := make([]support.StackDelta, numDeltas) - innerKey := uint32(0) - stackDelta := support.StackDelta{} + // Prepare values for batch update. for index, delta := range deltas { - stackDelta.AddrLow = delta.AddressLow - stackDelta.UnwindInfo = delta.UnwindInfo - innerKey = uint32(index) - if err := innerMap.Update(unsafe.Pointer(&innerKey), unsafe.Pointer(&stackDelta), - cebpf.UpdateAny); err != nil { - return 0, impl.trackMapError(metrics.IDExeIDToStackDeltasUpdate, fmt.Errorf( - "failed to insert element %d for 0x%x into exeIDTostack_deltas: %v", - index, fileID, err)) - } + innerKeys[index] = uint32(index) + stackDeltas[index].AddrLow = delta.AddressLow + stackDeltas[index].UnwindInfo = delta.UnwindInfo } + _, err = innerMap.BatchUpdate( + ptrCastMarshaler[uint32](innerKeys), + ptrCastMarshaler[support.StackDelta](stackDeltas), + &cebpf.BatchOptions{Flags: uint64(cebpf.UpdateAny)}) + if err != nil { + return 0, impl.trackMapError(metrics.IDExeIDToStackDeltasBatchUpdate, + fmt.Errorf("failed to batch insert %d elements for 0x%x "+ + "into exeIDTostack_deltas: %v", + numDeltas, fileID, err)) + } return mapID, nil } @@ -897,22 +875,12 @@ func (impl *ebpfMapsImpl) UpdateStackDeltaPages(fileID host.FileID, numDeltasPer firstDelta += uint32(numDeltas) } - if impl.hasGenericBatchOperations { - _, err := impl.StackDeltaPageToInfo.BatchUpdate( - ptrCastMarshaler[support.StackDeltaPageKey](keys), - ptrCastMarshaler[support.StackDeltaPageInfo](values), - &cebpf.BatchOptions{Flags: uint64(cebpf.UpdateNoExist)}) - return impl.trackMapError(metrics.IDStackDeltaPageToInfoBatchUpdate, err) - } + _, err := impl.StackDeltaPageToInfo.BatchUpdate( + ptrCastMarshaler[support.StackDeltaPageKey](keys), + ptrCastMarshaler[support.StackDeltaPageInfo](values), + &cebpf.BatchOptions{Flags: uint64(cebpf.UpdateNoExist)}) + return impl.trackMapError(metrics.IDStackDeltaPageToInfoBatchUpdate, err) - for index := range keys { - if err := impl.trackMapError(metrics.IDStackDeltaPageToInfoUpdate, - impl.StackDeltaPageToInfo.Update(unsafe.Pointer(&keys[index]), - unsafe.Pointer(&values[index]), cebpf.UpdateNoExist)); err != nil { - return err - } - } - return nil } // DeleteStackDeltaPage removes the entry specified by fileID and page from the eBPF map. @@ -1017,24 +985,6 @@ func (impl *ebpfMapsImpl) LookupPidPageInformation(pid libpf.PID, page uint64) ( return host.FileID(cValue.File_id), bias, nil } -// SupportsGenericBatchOperations returns true if the kernel supports eBPF batch operations -// on hash and array maps. -func (impl *ebpfMapsImpl) SupportsGenericBatchOperations() bool { - return impl.hasGenericBatchOperations -} - -// SupportsGenericBatchLookupAndDelete returns true if the kernel supports eBPF batch -// lookup-and-delete operations on hash and array maps. -func (impl *ebpfMapsImpl) SupportsGenericBatchLookupAndDelete() bool { - return impl.hasGenericBatchLookupAndDelete -} - -// SupportsLPMTrieBatchOperations returns true if the kernel supports eBPF batch operations -// on LPM trie maps. -func (impl *ebpfMapsImpl) SupportsLPMTrieBatchOperations() bool { - return impl.hasLPMTrieBatchOperations -} - // ptrCastMarshaler is a small wrapper type intended to be used with cilium's BatchUpdate and // BackDelete functions. // diff --git a/processmanager/ebpf/ebpf_integration_test.go b/processmanager/ebpf/ebpf_integration_test.go index 8d7915dbc..59a7f7861 100644 --- a/processmanager/ebpf/ebpf_integration_test.go +++ b/processmanager/ebpf/ebpf_integration_test.go @@ -15,6 +15,7 @@ import ( "go.opentelemetry.io/ebpf-profiler/libpf" "go.opentelemetry.io/ebpf-profiler/lpm" + "go.opentelemetry.io/ebpf-profiler/metrics" "go.opentelemetry.io/ebpf-profiler/rlimit" "go.opentelemetry.io/ebpf-profiler/support" ) @@ -34,6 +35,7 @@ func loadTracers(t *testing.T) *ebpfMapsImpl { return &ebpfMapsImpl{ PidPageToMappingInfo: pidPageToMappingInfo, + errCounter: make(map[metrics.MetricID]int64), } } diff --git a/processmanager/ebpfapi/ebpf.go b/processmanager/ebpfapi/ebpf.go index a750d2fef..0f8398138 100644 --- a/processmanager/ebpfapi/ebpf.go +++ b/processmanager/ebpfapi/ebpf.go @@ -56,14 +56,6 @@ type EbpfHandler interface { // CollectMetrics returns gathered errors for changes to eBPF maps. CollectMetrics() []metrics.Metric - // SupportsGenericBatchOperations returns true if the kernel supports eBPF batch operations - // on hash and array maps. - SupportsGenericBatchOperations() bool - - // SupportsGenericBatchLookupAndDelete returns true if the kernel supports eBPF batch - // lookup-and-delete operations on hash and array maps. - SupportsGenericBatchLookupAndDelete() bool - // SupportsLPMTrieBatchOperations returns true if the kernel supports eBPF batch operations // on LPM trie maps. SupportsLPMTrieBatchOperations() bool diff --git a/processmanager/processinfo.go b/processmanager/processinfo.go index be07b7835..604d80d7e 100644 --- a/processmanager/processinfo.go +++ b/processmanager/processinfo.go @@ -18,6 +18,7 @@ import ( "path" "slices" "sort" + "strings" "syscall" "time" @@ -189,7 +190,7 @@ func (pm *ProcessManager) handleNewInterpreter(pr process.Process, bias libpf.Ad return nil } -func (pm *ProcessManager) getELFInfo(pr process.Process, mapping *process.Mapping, +func (pm *ProcessManager) getELFInfo(pr process.Process, mapping *process.RawMapping, elfRef *pfelf.Reference, ) elfInfo { key := mapping.GetOnDiskFileIdentifier() @@ -224,7 +225,7 @@ func (pm *ProcessManager) getELFInfo(pr process.Process, mapping *process.Mappin return info } - baseName := path.Base(mapping.Path.String()) + baseName := path.Base(mapping.Path) if baseName == "/" { // There are circumstances where there is no filename. // E.g. kernel module 'bpfilter_umh' before Linux 5.9-rc1 uses @@ -332,8 +333,8 @@ func (pm *ProcessManager) processRemovedInterpreters(pid libpf.PID, var errInvalidVirtualAddress = errors.New("invalid ELF virtual address") -func (pm *ProcessManager) newFrameMapping(pr process.Process, m *process.Mapping) (libpf.FrameMapping, error) { - elfRef := pfelf.NewReference(m.Path.String(), pr) +func (pm *ProcessManager) newFrameMapping(pr process.Process, m *process.RawMapping) (libpf.FrameMapping, error) { + elfRef := pfelf.NewReference(m.Path, pr) defer elfRef.Close() info := pm.getELFInfo(pr, m, elfRef) @@ -395,34 +396,93 @@ func compareMapping(a, b Mapping) int { return 0 } -// synchronizeMappings synchronizes executable mappings for the given PID. -// This method will be called when a PID is first encountered or when the eBPF -// code encounters an address in an executable mapping that HA has no information -// on. Therefore, executable mapping synchronization takes place lazily on-demand, -// and map/unmap operations are not precisely tracked (reduce processing load). -// This means that at any point, we may have cached stale (or miss) executable -// mappings. The expectation is that stale mappings will disappear and new -// mappings cached at the next synchronization triggered by process exit or -// unknown address encountered. +// processPIDExit informs the ProcessManager that a process exited and no longer will be scheduled. +// exitKTime is stored for later processing in ProcessedUntil, when traces up to this time have been +// processed. There can be a race condition if we can not clean up the references for this process +// fast enough and this particular pid is reused again by the system. +func (pm *ProcessManager) processPIDExit(pid libpf.PID) { + exitKTime := times.GetKTime() + log.Debugf("- PID: %v", pid) + + var err error + defer func() { + if err != nil { + log.Error(err) + } + }() + defer pm.ebpf.RemoveReportedPID(pid) + pm.mu.Lock() + defer pm.mu.Unlock() + + info, pidExists := pm.pidToProcessInfo[pid] + if !pidExists { + log.Debugf("Skip process exit handling for unknown PID %d", pid) + return + } + + // processPIDExit may be called multiple times in short succession + // for the same PID, don't update exitKTime if we've previously recorded it. + if _, pidExitProcessed := pm.exitEvents[pid]; !pidExitProcessed { + pm.exitEvents[pid] = exitKTime + } else { + log.Debugf("Skip duplicate process exit handling for PID %d", pid) + return + } + + // Delete all entries we have for this particular PID from pid_page_to_mapping_info. + deleted, err2 := pm.ebpf.DeletePidPageMappingInfo(pid, []lpm.Prefix{dummyPrefix}) + if err2 != nil { + err = errors.Join(err, fmt.Errorf("failed to delete dummy prefix for PID %d: %v", + pid, err2)) + } + pm.pidPageToMappingInfoSize -= uint64(deleted) + + for idx := range info.mappings { + pm.processRemovedMapping(pid, &info.mappings[idx]) + } + pm.processRemovedInterpreters(pid, libpf.Set[util.OnDiskFileIdentifier]{}) +} + +// SynchronizeProcess triggers ProcessManager to update its internal information +// about a process. It synchronizes executable mappings for the given PID by +// parsing /proc/PID/maps and building the internal mapping state directly in +// a single pass. This method will be called when a PID is first encountered or +// when the eBPF code encounters an address in an executable mapping that HA has +// no information on. Therefore, executable mapping synchronization takes place +// lazily on-demand, and map/unmap operations are not precisely tracked (reduce +// processing load). This means that at any point, we may have cached stale (or +// miss) executable mappings. The expectation is that stale mappings will +// disappear and new mappings cached at the next synchronization triggered by +// process exit or unknown address encountered. // // TODO: Periodic synchronization of mappings for every tracked PID. -func (pm *ProcessManager) synchronizeMappings(pr process.Process, - processMappings []process.Mapping) bool { +func (pm *ProcessManager) SynchronizeProcess(pr process.Process) { pid := pr.PID() + log.Debugf("= PID: %v", pid) + + // Abort early if process is waiting for cleanup in ProcessedUntil + pm.mu.Lock() + _, ok := pm.exitEvents[pid] + pm.mu.Unlock() + + if ok { + log.Debugf("PID %v waiting for cleanup, aborting SynchronizeProcess", pid) + pm.ebpf.RemoveReportedPID(pid) + return + } // Get current executable name - exe, err := pr.GetExe() - if err != nil && !os.IsNotExist(err) { + exe, exeErr := pr.GetExe() + if exeErr != nil && !os.IsNotExist(exeErr) { // The /proc/PID/exe returns "not exists" error also in // the case of main thread exit. Ignore it. - log.Warnf("Failed to get executable of process %d: %v", pid, err) } pm.mu.Lock() info := pm.getPidInformation(pid, pr) if info == nil { pm.mu.Unlock() - return false + return } // Check if process meta needs an update updateProcessMeta := exe != libpf.NullString && exe != info.meta.Executable @@ -443,50 +503,118 @@ func (pm *ProcessManager) synchronizeMappings(pr process.Process, mpRemove[uint64(m.Vaddr)] = m } - // Generate the list of new processmanager mappings and interpreters. - // Reuse existing mappings if possible. - mappings := make([]Mapping, 0, len(processMappings)) - mpAdd := make([]*Mapping, 0, len(processMappings)) + // interpreterMappings collects the subset of mappings relevant to interpreters: + // executable anonymous mappings (JIT) and DLL file-backed mappings (.NET PE). + // They are in /proc/PID/maps order (ascending Vaddr), not sorted otherwise. + interpreterMappings := make([]process.RawMapping, 0, 8) interpretersValid := make(libpf.Set[util.OnDiskFileIdentifier], numInterpreters) - for idx := range processMappings { - m := &processMappings[idx] - if !m.IsExecutable() || m.IsAnonymous() { - continue + capHint := max(32, min(len(oldMappings), 256)) + mappings := make([]Mapping, 0, capHint) + mpAdd := make([]*Mapping, 0, capHint) + + pm.mappingStats.numProcAttempts.Add(1) + start := time.Now() + + // This callback processes each memory mapping, keeping only executable + // file-backed mappings and anonymous executable/DLL mappings needed by interpreters. + // All other mappings are skipped. + numParseErrors, err := pr.IterateMappings(func(m process.RawMapping) bool { + // Executable mappings and VDSO, converted directly to libpf.FrameMapping + mappingNeeded := m.IsExecutable() && !m.IsAnonymous() + // Needed for JIT mappings (Hotspot, V8, BEAM, etc.) + interpreterNeeded := m.IsExecutable() && m.IsAnonymous() + // Needed by .NET to retrieve PE assembly mappings + interpreterNeeded = interpreterNeeded || strings.HasSuffix(m.Path, ".dll") + if !mappingNeeded && !interpreterNeeded { + return true } - var fm libpf.FrameMapping - if oldm, ok := mpRemove[m.Vaddr]; ok { - if oldm.Length == m.Length && oldm.Device == m.Device && oldm.Inode == m.Inode { - delete(mpRemove, m.Vaddr) - fm = oldm.FrameMapping + m.Path = libpf.Intern(m.Path).String() + + if mappingNeeded { + var fm libpf.FrameMapping + if oldm, ok := mpRemove[m.Vaddr]; ok { + if oldm.Length == m.Length && oldm.Device == m.Device && oldm.Inode == m.Inode { + delete(mpRemove, m.Vaddr) + fm = oldm.FrameMapping + } } - } - newMapping := false - if !fm.Valid() { - newMapping = true - var err error - fm, err = pm.newFrameMapping(pr, m) - if err != nil { - // newFrameMapping logged the message if needed - continue + newMapping := false + if !fm.Valid() { + newMapping = true + // Error is expected for non-ELF files (e.g. PE DLL); + // fm will be invalid and the mapping skipped below but will enter the interpreter mappings block. + fm, _ = pm.newFrameMapping(pr, &m) + } + if fm.Valid() { + key := m.GetOnDiskFileIdentifier() + interpretersValid[key] = libpf.Void{} + + mappings = append(mappings, Mapping{ + Vaddr: libpf.Address(m.Vaddr), + Length: m.Length, + Device: m.Device, + Inode: m.Inode, + FrameMapping: fm, + }) + if newMapping { + mpAdd = append(mpAdd, &mappings[len(mappings)-1]) + } } } - key := m.GetOnDiskFileIdentifier() - interpretersValid[key] = libpf.Void{} - - mappings = append(mappings, Mapping{ - Vaddr: libpf.Address(m.Vaddr), - Length: m.Length, - Device: m.Device, - Inode: m.Inode, - FrameMapping: fm, - }) - if newMapping { - mpAdd = append(mpAdd, &mappings[len(mappings)-1]) + if interpreterNeeded { + interpreterMappings = append(interpreterMappings, m) + } + return true + }) + + elapsed := time.Since(start) + pm.mappingStats.numProcParseErrors.Add(numParseErrors) + + if err != nil { + switch { + case errors.Is(err, process.ErrCallbackStopped): + // Defensive: the current callback does not stop early, but the + // IterateMappings contract allows it. Treat as non-fatal and + // continue with whatever mappings were collected so far. + err = nil + case os.IsPermission(err): + // Ignore the synchronization completely in case of permission + // error. This implies the process is still alive, but we cannot + // inspect it. Exiting here keeps the PID in the eBPF maps so + // we avoid a notification flood to resynchronize. + pm.mappingStats.errProcPerm.Add(1) + return + case errors.Is(err, process.ErrNoMappings): + // When no mappings can be extracted but the process is still alive, + // do not trigger a process exit to avoid unloading process metadata. + // As it's likely that a future iteration can extract mappings from a + // different thread in the process, notify eBPF to enable further notifications. + pm.ebpf.RemoveReportedPID(pid) + return + case os.IsNotExist(err): + // Since listing /proc and opening files in there later is inherently racy, + // we expect to lose the race sometimes and thus expect to hit os.IsNotExist. + pm.mappingStats.errProcNotExist.Add(1) + log.Debugf("removing pid due to mappings read error: %v", err) + pm.processPIDExit(pid) + return + default: + if e, ok := err.(*os.PathError); ok && e.Err == syscall.ESRCH { + // If the process exits while reading its /proc/$PID/maps, the kernel will + // return ESRCH. Handle it as if the process did not exist. + pm.mappingStats.errProcESRCH.Add(1) + } + log.Debugf("removing pid due to mappings read error: %v", err) + pm.processPIDExit(pid) + return } } + util.AtomicUpdateMaxUint32(&pm.mappingStats.maxProcParseUsec, uint32(elapsed.Microseconds())) + pm.mappingStats.totalProcParseUsec.Add(uint32(elapsed.Microseconds())) + // Detach removed interpreters and remove old mappings numChanges := uint64(0) for _, m := range mpRemove { @@ -525,7 +653,7 @@ func (pm *ProcessManager) synchronizeMappings(pr process.Process, // Synchronize all interpreters with updated mappings for _, instance := range interpreters { - err := instance.SynchronizeMappings(pm.ebpf, pm.exeReporter, pr, processMappings) + err := instance.SynchronizeMappings(pm.ebpf, pm.exeReporter, pr, interpreterMappings) if err != nil { if alive, _ := isPIDLive(pid); alive { log.Errorf("Failed to handle new anonymous mapping for PID %d: %v", pid, err) @@ -540,118 +668,8 @@ func (pm *ProcessManager) synchronizeMappings(pr process.Process, log.Debugf("Added %v mappings, removed %v mappings for PID %v with %d interpreters", len(mpAdd), len(mpRemove), pid, len(interpreters)) } - return newProcess -} - -// processPIDExit informs the ProcessManager that a process exited and no longer will be scheduled. -// exitKTime is stored for later processing in ProcessedUntil, when traces up to this time have been -// processed. There can be a race condition if we can not clean up the references for this process -// fast enough and this particular pid is reused again by the system. -func (pm *ProcessManager) processPIDExit(pid libpf.PID) { - exitKTime := times.GetKTime() - log.Debugf("- PID: %v", pid) - - var err error - defer func() { - if err != nil { - log.Error(err) - } - }() - defer pm.ebpf.RemoveReportedPID(pid) - pm.mu.Lock() - defer pm.mu.Unlock() - - info, pidExists := pm.pidToProcessInfo[pid] - if !pidExists { - log.Debugf("Skip process exit handling for unknown PID %d", pid) - return - } - - // processPIDExit may be called multiple times in short succession - // for the same PID, don't update exitKTime if we've previously recorded it. - if _, pidExitProcessed := pm.exitEvents[pid]; !pidExitProcessed { - pm.exitEvents[pid] = exitKTime - } else { - log.Debugf("Skip duplicate process exit handling for PID %d", pid) - return - } - - // Delete all entries we have for this particular PID from pid_page_to_mapping_info. - deleted, err2 := pm.ebpf.DeletePidPageMappingInfo(pid, []lpm.Prefix{dummyPrefix}) - if err2 != nil { - err = errors.Join(err, fmt.Errorf("failed to delete dummy prefix for PID %d: %v", - pid, err2)) - } - pm.pidPageToMappingInfoSize -= uint64(deleted) - - for idx := range info.mappings { - pm.processRemovedMapping(pid, &info.mappings[idx]) - } - pm.processRemovedInterpreters(pid, libpf.Set[util.OnDiskFileIdentifier]{}) -} - -// SynchronizeProcess triggers ProcessManager to update its internal information -// about a process. This includes process exit information as well as changed memory mappings. -func (pm *ProcessManager) SynchronizeProcess(pr process.Process) { - pid := pr.PID() - log.Debugf("= PID: %v", pid) - - // Abort early if process is waiting for cleanup in ProcessedUntil - pm.mu.Lock() - _, ok := pm.exitEvents[pid] - pm.mu.Unlock() - - if ok { - log.Debugf("PID %v waiting for cleanup, aborting SynchronizeProcess", pid) - pm.ebpf.RemoveReportedPID(pid) - return - } - - pm.mappingStats.numProcAttempts.Add(1) - start := time.Now() - mappings, numParseErrors, err := pr.GetMappings() - elapsed := time.Since(start) - pm.mappingStats.numProcParseErrors.Add(numParseErrors) - - if err != nil { - if os.IsPermission(err) { - // Ignore the synchronization completely in case of permission - // error. This implies the process is still alive, but we cannot - // inspect it. Exiting here keeps the PID in the eBPF maps so - // we avoid a notification flood to resynchronize. - pm.mappingStats.errProcPerm.Add(1) - return - } - - if errors.Is(err, process.ErrNoMappings) { - // When no mappings can be extracted but the process is still alive, - // do not trigger a process exit to avoid unloading process metadata. - // As it's likely that a future iteration can extract mappings from a - // different thread in the process, notify eBPF to enable further notifications. - pm.ebpf.RemoveReportedPID(pid) - return - } - - // All other errors imply that the process has exited. - if os.IsNotExist(err) { - // Since listing /proc and opening files in there later is inherently racy, - // we expect to lose the race sometimes and thus expect to hit os.IsNotExist. - pm.mappingStats.errProcNotExist.Add(1) - } else if e, ok := err.(*os.PathError); ok && e.Err == syscall.ESRCH { - // If the process exits while reading its /proc/$PID/maps, the kernel will - // return ESRCH. Handle it as if the process did not exist. - pm.mappingStats.errProcESRCH.Add(1) - } - // Clean up, and notify eBPF. - log.Debugf("removing pid due to mappings read error: %v", err) - pm.processPIDExit(pid) - return - } - - util.AtomicUpdateMaxUint32(&pm.mappingStats.maxProcParseUsec, uint32(elapsed.Microseconds())) - pm.mappingStats.totalProcParseUsec.Add(uint32(elapsed.Microseconds())) - if pm.synchronizeMappings(pr, mappings) { + if newProcess { log.Debugf("+ PID: %v", pid) // TODO: Fine-grained reported_pids handling (evaluate per-PID mapping // synchronization based on per-PID state such as time since last diff --git a/processmanager/processinfo_test.go b/processmanager/processinfo_test.go index 8d6647508..053200d59 100644 --- a/processmanager/processinfo_test.go +++ b/processmanager/processinfo_test.go @@ -63,7 +63,6 @@ func TestAssignLibcInfoMergesLibcInfo(t *testing.T) { libc.DTVInfo{ Offset: -8, Multiplier: 16, - Indirect: 1, }, } diff --git a/reporter/iface.go b/reporter/iface.go index e1c91a530..60ce80c13 100644 --- a/reporter/iface.go +++ b/reporter/iface.go @@ -40,9 +40,9 @@ type ExecutableMetadata struct { // Process is the interface to the process holding the file. Process process.Process - // Mapping is the process.Mapping file. Process.OpenMappingFile can be used + // Mapping is the process.RawMapping file. Process.OpenMappingFile can be used // to open the file if needed. - Mapping *process.Mapping + Mapping *process.RawMapping // DebuglinkFileName is the path to the matching debug file // from the .gnu.debuglink, if any. The caller should diff --git a/reporter/internal/pdata/generate.go b/reporter/internal/pdata/generate.go index 830c77ca8..9aeb4a3aa 100644 --- a/reporter/internal/pdata/generate.go +++ b/reporter/internal/pdata/generate.go @@ -61,6 +61,7 @@ func (p *Pdata) Generate(tree samples.TraceEventsTree, mappingSet := make(orderedset.OrderedSet[libpf.FrameMapping], 64) stackSet := make(orderedset.OrderedSet[stackInfo], 64) locationSet := make(orderedset.OrderedSet[locationInfo], 64) + linkSet := make(orderedset.OrderedSet[linkInfo], 64) // By specification, the first element should be empty. stringSet.Add("") @@ -68,6 +69,7 @@ func (p *Pdata) Generate(tree samples.TraceEventsTree, mappingSet.Add(libpf.FrameMapping{}) stackSet.Add(stackInfo{}) locationSet.Add(locationInfo{}) + linkSet.Add(linkInfo{}) dic.LinkTable().AppendEmpty() dic.MappingTable().AppendEmpty() @@ -103,7 +105,7 @@ func (p *Pdata) Generate(tree samples.TraceEventsTree, prof := sp.Profiles().AppendEmpty() if err := p.setProfile(dic, attrMgr, - stringSet, funcSet, mappingSet, stackSet, locationSet, + stringSet, funcSet, mappingSet, stackSet, locationSet, linkSet, origin, toEvents.Events[origin], prof, collectionStartTime, collectionEndTime); err != nil { return profiles, err @@ -143,6 +145,7 @@ func (p *Pdata) setProfile( mappingSet orderedset.OrderedSet[libpf.FrameMapping], stackSet orderedset.OrderedSet[stackInfo], locationSet orderedset.OrderedSet[locationInfo], + linkSet orderedset.OrderedSet[linkInfo], origin libpf.Origin, events samples.SampleToEvents, profile pprofile.Profile, @@ -177,6 +180,21 @@ func (p *Pdata) setProfile( sample.Values().Append(traceInfo.OffTimes...) } + if sampleKey.SpanID != libpf.InvalidAPMSpanID && + sampleKey.TraceID != libpf.InvalidAPMTraceID { + link, ok := linkSet.AddWithCheck(linkInfo{ + traceID: sampleKey.TraceID, + spanID: sampleKey.SpanID, + }) + if !ok { + l := dic.LinkTable().AppendEmpty() + l.SetSpanID(pcommon.SpanID(sampleKey.SpanID)) + l.SetTraceID(pcommon.TraceID(sampleKey.TraceID)) + + } + sample.SetLinkIndex(link) + } + locationIndices := make([]int32, 0, len(traceInfo.Frames)) // Walk every frame of the trace. for _, uniqueFrame := range traceInfo.Frames { diff --git a/reporter/internal/pdata/generate_test.go b/reporter/internal/pdata/generate_test.go index f9fc35293..ef86f701d 100644 --- a/reporter/internal/pdata/generate_test.go +++ b/reporter/internal/pdata/generate_test.go @@ -593,7 +593,15 @@ func TestGenerate_NativeFrame(t *testing.T) { } events := map[libpf.Origin]samples.SampleToEvents{ support.TraceOriginSampling: { - {}: &samples.TraceEvents{ + { + Hash: libpf.NewTraceHash(0, 1), + Comm: libpf.Intern("abc"), + TID: 42, + CPU: 73, + SpanID: libpf.APMSpanID{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, + TraceID: libpf.APMTraceID{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}, + }: &samples.TraceEvents{ Frames: singleFrameNative(mappingFile, 0x1000, 0x1000, 0x2000, 0x100), Timestamps: []uint64{ uint64(time.Unix(1010, 0).UnixNano()), @@ -668,6 +676,50 @@ func TestGenerate_NativeFrame(t *testing.T) { // since it's resolved by the backend. The function table should be empty. assert.Equal(t, 1, dic.FunctionTable().Len(), "Function table should be empty for native frames") + + // Verify SpanID and TraceID are set via Link + linkIndex := sample.LinkIndex() + assert.Greater(t, linkIndex, int32(0), "Sample should have a link set (index > 0, since 0 is dummy)") + link := dic.LinkTable().At(int(linkIndex)) + expectedSpanID := pcommon.SpanID{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7} + expectedTraceID := pcommon.TraceID{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27} + assert.Equal(t, expectedSpanID, link.SpanID()) + assert.Equal(t, expectedTraceID, link.TraceID()) + + // Verify Comm, TID, and CPU are set in sample attributes + attributeIndices := sample.AttributeIndices().AsRaw() + assert.NotEmpty(t, attributeIndices, "Sample should have attributes") + + attributeTable := dic.AttributeTable() + stringTable := dic.StringTable() + + foundComm := false + foundTID := false + foundCPU := false + + for _, attrIdx := range attributeIndices { + attr := attributeTable.At(int(attrIdx)) + keyStrIdx := attr.KeyStrindex() + key := stringTable.At(int(keyStrIdx)) + + switch key { + case string(semconv.ThreadNameKey): + assert.Equal(t, "abc", attr.Value().Str()) + foundComm = true + case string(semconv.ThreadIDKey): + assert.Equal(t, int64(42), attr.Value().Int()) + foundTID = true + case string(semconv.CPULogicalNumberKey): + assert.Equal(t, int64(73), attr.Value().Int()) + foundCPU = true + } + } + + assert.True(t, foundComm, "Sample should have Comm attribute set") + assert.True(t, foundTID, "Sample should have TID attribute set") + assert.True(t, foundCPU, "Sample should have CPU attribute set") + } func TestStackTableOrder(t *testing.T) { @@ -761,7 +813,15 @@ func TestGenerate_Validate(t *testing.T) { } events := map[libpf.Origin]samples.SampleToEvents{ support.TraceOriginSampling: { - {}: &samples.TraceEvents{ + { + Hash: libpf.NewTraceHash(0, 1), + Comm: libpf.Intern("abc"), + TID: 42, + CPU: 73, + SpanID: libpf.APMSpanID{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, + TraceID: libpf.APMTraceID{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}, + }: &samples.TraceEvents{ Frames: singleFrameTrace(libpf.PythonFrame, mapping, 0x30, funcName, filePath, 123), Timestamps: []uint64{42}, diff --git a/reporter/internal/pdata/helper.go b/reporter/internal/pdata/helper.go index 0a86418aa..7927f0f95 100644 --- a/reporter/internal/pdata/helper.go +++ b/reporter/internal/pdata/helper.go @@ -35,3 +35,9 @@ func hashLocationIndices(locationIndices []int32) uint64 { h.Write(pfunsafe.FromSlice(locationIndices)) return h.Sum64() } + +// linkInfo is a helper used to deduplicate Links. +type linkInfo struct { + spanID libpf.APMSpanID + traceID libpf.APMTraceID +} diff --git a/reporter/samples/samples.go b/reporter/samples/samples.go index 37362b676..5dc165869 100644 --- a/reporter/samples/samples.go +++ b/reporter/samples/samples.go @@ -19,6 +19,8 @@ type TraceEventMeta struct { Origin libpf.Origin OffTime int64 PID, TID libpf.PID + SpanID libpf.APMSpanID + TraceID libpf.APMTraceID // OriginData carries optional Origin-specific payload. OriginData any @@ -81,4 +83,7 @@ type SampleKey struct { TID int64 CPU int64 + + SpanID libpf.APMSpanID + TraceID libpf.APMTraceID } diff --git a/rust-crates/symblib/src/fileid.rs b/rust-crates/symblib/src/fileid.rs index cb1473cc9..a0a5770a6 100644 --- a/rust-crates/symblib/src/fileid.rs +++ b/rust-crates/symblib/src/fileid.rs @@ -6,7 +6,6 @@ use base64::Engine; use sha2::digest::FixedOutput; use sha2::Digest as _; -use std::io::Read as _; use std::{fmt, fs, io, path}; /// Size of the head and tail blocks used for partially hashing ELF files. @@ -44,12 +43,17 @@ impl FileId { // Hash first 4096 bytes. stream.seek(io::SeekFrom::Start(0))?; - io::copy(&mut stream.by_ref().take(PARTIAL_HASH_SIZE), &mut hasher)?; + let mut buf = [0u8; 4096]; + let to_read = (PARTIAL_HASH_SIZE as usize).min(buf.len()); + let n = stream.read(&mut buf[..to_read])?; + hasher.update(&buf[..n]); // Hash last 4096 bytes. let tail_start = stream_len.saturating_sub(PARTIAL_HASH_SIZE); stream.seek(io::SeekFrom::Start(tail_start))?; - io::copy(&mut stream.by_ref().take(PARTIAL_HASH_SIZE), &mut hasher)?; + let to_read = (PARTIAL_HASH_SIZE as usize).min(buf.len()); + let n = stream.read(&mut buf[..to_read])?; + hasher.update(&buf[..n]); // Hash length. hasher.update(u64::to_be_bytes(stream_len)); diff --git a/support/ebpf/bpfdefs.h b/support/ebpf/bpfdefs.h index 6e70738e8..feb2b43a1 100644 --- a/support/ebpf/bpfdefs.h +++ b/support/ebpf/bpfdefs.h @@ -195,7 +195,7 @@ static long (*bpf_get_attach_cookie)(void *ctx) = (void *)BPF_FUNC_get_attach_co // 5.4 kernels. #define printt(fmt, ...) \ ({ \ - const char ____fmt[] = fmt "\n"; \ + const char ____fmt[] = fmt; \ bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ }) diff --git a/support/ebpf/tracer.ebpf.amd64 b/support/ebpf/tracer.ebpf.amd64 index b04375369..4cc8dd8a0 100644 Binary files a/support/ebpf/tracer.ebpf.amd64 and b/support/ebpf/tracer.ebpf.amd64 differ diff --git a/support/ebpf/tracer.ebpf.arm64 b/support/ebpf/tracer.ebpf.arm64 index a7ce37b71..0f9a1361a 100644 Binary files a/support/ebpf/tracer.ebpf.arm64 and b/support/ebpf/tracer.ebpf.arm64 differ diff --git a/support/ebpf/types.h b/support/ebpf/types.h index d82a373f6..88d6af862 100644 --- a/support/ebpf/types.h +++ b/support/ebpf/types.h @@ -439,15 +439,16 @@ typedef struct TSDInfo { } TSDInfo; // DTVInfo contains data needed to read Thread Local Storage (TLS) values, which -// are located using the Dynamic Thread Vector (DTV) +// are located using the Dynamic Thread Vector (DTV). +// DTV access is always indirect: TP+offset yields a pointer to the DTV array, +// which must be dereferenced before indexing by module ID. This is true for +// both glibc and musl (the DTV is a separately-allocated array, not inline +// in the thread control block). typedef struct DTVInfo { - // Offset is the offset of DTV from FS base (or from thread pointer) + // Offset is the offset of the DTV pointer from the thread pointer base. s16 offset; - // Multiplier is the size of each DTV entry in bytes - // Typically 8 bytes on 64bit musl and 16 bytes on 64bit glibc + // Multiplier is the size of each DTV entry in bytes. u8 multiplier; - // Indirect is 0 if DTV is at FS+offset, 1 if at [FS+0]+offset - u8 indirect; } DTVInfo; // DotnetProcInfo is a container for the data needed to build stack trace for a dotnet process. diff --git a/support/types.go b/support/types.go index caa65ad5a..4ec1722ab 100644 --- a/support/types.go +++ b/support/types.go @@ -156,7 +156,7 @@ type TSDInfo struct { type DTVInfo struct { Offset int16 Multiplier uint8 - Indirect uint8 + Pad_cgo_0 [1]byte } type Trace struct { Pid uint32 diff --git a/tools.mod b/tools.mod index f5354610f..58b691af8 100644 --- a/tools.mod +++ b/tools.mod @@ -7,43 +7,53 @@ tool ( github.com/google/go-licenses/v2 github.com/jcchavezs/porto/cmd/porto go.opentelemetry.io/collector/cmd/builder + go.opentelemetry.io/collector/cmd/mdatagen gotest.tools/gotestsum ) require ( - github.com/aws/aws-sdk-go-v2 v1.41.4 - github.com/aws/aws-sdk-go-v2/config v1.32.12 - github.com/aws/aws-sdk-go-v2/service/s3 v1.97.2 + github.com/aws/aws-sdk-go-v2 v1.41.5 + github.com/aws/aws-sdk-go-v2/config v1.32.14 + github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0 github.com/cilium/ebpf v0.21.0 + github.com/coreos/pkg v0.0.0-20240122114842-bbd7aa9bf6fb github.com/elastic/go-freelru v0.16.0 github.com/elastic/go-perf v0.0.0-20260224073651-af0ee0c731b7 github.com/google/uuid v1.6.0 github.com/klauspost/compress v1.18.5 github.com/mdlayher/kobject v0.0.0-20200520190114-19ca17470d7d github.com/minio/sha256-simd v1.0.1 + github.com/moby/moby/api v1.54.2 github.com/open-telemetry/sig-profiling/tools/profcheck v0.0.0-20260303084341-52f633d434c9 + github.com/parca-dev/oomprof v0.1.6 + github.com/parca-dev/usdt v0.0.2 github.com/peterbourgon/ff/v3 v3.4.0 + github.com/sirupsen/logrus v1.9.4 github.com/stretchr/testify v1.11.1 + github.com/testcontainers/testcontainers-go v0.42.0 github.com/zeebo/xxh3 v1.1.0 - go.opentelemetry.io/collector/component v1.54.0 - go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 - go.opentelemetry.io/collector/consumer/consumertest v0.148.0 - go.opentelemetry.io/collector/consumer/xconsumer v0.148.0 - go.opentelemetry.io/collector/pdata v1.54.0 - go.opentelemetry.io/collector/pdata/pprofile v0.148.0 - go.opentelemetry.io/collector/receiver v1.54.0 - go.opentelemetry.io/collector/receiver/receivertest v0.148.0 - go.opentelemetry.io/collector/receiver/xreceiver v0.148.0 - go.opentelemetry.io/otel v1.42.0 - go.opentelemetry.io/otel/metric v1.42.0 + go.opentelemetry.io/collector/component v1.55.0 + go.opentelemetry.io/collector/component/componenttest v0.149.0 + go.opentelemetry.io/collector/confmap v1.55.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.149.0 + go.opentelemetry.io/collector/consumer/consumertest v0.149.0 + go.opentelemetry.io/collector/consumer/xconsumer v0.149.0 + go.opentelemetry.io/collector/pdata v1.55.0 + go.opentelemetry.io/collector/pdata/pprofile v0.149.0 + go.opentelemetry.io/collector/receiver v1.55.0 + go.opentelemetry.io/collector/receiver/receivertest v0.149.0 + go.opentelemetry.io/collector/receiver/xreceiver v0.149.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/metric v1.43.0 go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 + go.uber.org/goleak v1.3.0 go.uber.org/zap/exp v0.3.0 golang.org/x/arch v0.25.0 golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 golang.org/x/mod v0.34.0 golang.org/x/sync v0.20.0 golang.org/x/sys v0.42.0 - google.golang.org/grpc v1.79.3 + google.golang.org/grpc v1.80.0 google.golang.org/protobuf v1.36.11 ) @@ -52,6 +62,7 @@ require ( 4d63.com/gochecknoglobals v0.2.2 // indirect codeberg.org/chavacava/garif v0.2.0 // indirect codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect + dario.cat/mergo v1.0.2 // indirect dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect dev.gaijin.team/go/golib v0.6.0 // indirect github.com/4meepo/tagalign v1.4.3 // indirect @@ -61,9 +72,11 @@ require ( github.com/Antonboom/errname v1.1.1 // indirect github.com/Antonboom/nilnil v1.1.1 // indirect github.com/Antonboom/testifylint v1.6.4 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/BurntSushi/toml v1.6.0 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/MirrexOne/unqueryvet v1.5.4 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect github.com/alecthomas/chroma/v2 v2.23.1 // indirect @@ -76,20 +89,20 @@ require ( github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect github.com/ashanbrown/makezero/v2 v2.1.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.19.12 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.14 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 // indirect github.com/aws/smithy-go v1.24.2 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -104,6 +117,7 @@ require ( github.com/butuzov/mirror v1.3.0 // indirect github.com/catenacyber/perfsprint v0.10.1 // indirect github.com/ccojocar/zxcvbn-go v1.0.4 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charithe/durationcheck v0.0.11 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect @@ -112,16 +126,26 @@ require ( github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/term v0.2.1 // indirect github.com/ckaznocha/intrange v0.3.1 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect github.com/daixiang0/gci v0.13.7 // indirect github.com/dave/dst v0.27.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dnephin/pflag v1.0.7 // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/ebitengine/purego v0.10.0 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.19.0 // indirect github.com/fatih/structtag v1.2.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/firefart/nonamedreturns v1.0.6 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect @@ -129,6 +153,7 @@ require ( github.com/go-critic/go-critic v0.14.3 // 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.2.6 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect github.com/go-toolsmith/astequal v1.2.0 // indirect @@ -157,6 +182,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-licenses/v2 v2.0.1 // indirect github.com/google/licenseclassifier/v2 v2.0.0 // indirect + github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gordonklaus/ineffassign v0.2.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect @@ -186,7 +212,7 @@ require ( github.com/knadh/koanf/providers/env/v2 v2.0.0 // indirect github.com/knadh/koanf/providers/file v1.2.1 // indirect github.com/knadh/koanf/providers/fs v1.0.0 // indirect - github.com/knadh/koanf/v2 v2.3.3 // indirect + github.com/knadh/koanf/v2 v2.3.4 // indirect github.com/kulti/thelper v0.7.1 // indirect github.com/kunwardeep/paralleltest v1.0.15 // indirect github.com/lasiar/canonicalheader v1.1.2 // indirect @@ -198,8 +224,9 @@ require ( github.com/ldez/usetesting v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/macabu/inamedparam v0.2.0 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect github.com/manuelarte/funcorder v0.5.0 // indirect github.com/maratori/testableexamples v1.0.1 // indirect @@ -216,6 +243,14 @@ require ( github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.2.0 // indirect + github.com/moby/moby/client v0.4.0 // indirect + github.com/moby/patternmatcher v0.6.1 // 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/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/moricho/tparallel v0.3.2 // indirect @@ -224,10 +259,13 @@ require ( github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect github.com/nunnatsa/ginkgolinter v0.23.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/otiai10/copy v1.14.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect @@ -248,7 +286,7 @@ require ( github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 // indirect github.com/sergi/go-diff v1.2.0 // indirect - github.com/sirupsen/logrus v1.9.4 // indirect + github.com/shirou/gopsutil/v4 v4.26.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/sonatard/noctx v0.5.1 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect @@ -260,11 +298,13 @@ require ( github.com/spf13/viper v1.12.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.3.1 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/objx v0.5.3 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/tetafro/godot v1.5.4 // indirect github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect github.com/timonwong/loggercheck v0.11.0 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.2.0 // indirect @@ -276,6 +316,7 @@ require ( github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.3.0 // indirect github.com/ykadowak/zerologlint v0.1.5 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect gitlab.com/bosi/decorder v0.4.2 // indirect go-simpler.org/musttag v0.14.0 // indirect go-simpler.org/sloglint v0.11.1 // indirect @@ -283,27 +324,30 @@ require ( go.augendre.info/fatcontext v0.9.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/collector/cmd/builder v0.148.0 // indirect - go.opentelemetry.io/collector/component/componenttest v0.148.0 // indirect - go.opentelemetry.io/collector/confmap v1.54.0 // indirect - go.opentelemetry.io/collector/consumer v1.54.0 // indirect - go.opentelemetry.io/collector/consumer/consumererror v0.148.0 // indirect - go.opentelemetry.io/collector/featuregate v1.54.0 // indirect - go.opentelemetry.io/collector/internal/componentalias v0.148.0 // indirect - go.opentelemetry.io/collector/pipeline v1.54.0 // indirect + go.opentelemetry.io/collector/cmd/builder v0.149.0 // indirect + go.opentelemetry.io/collector/cmd/mdatagen v0.149.0 // indirect + go.opentelemetry.io/collector/confmap/provider/fileprovider v1.55.0 // indirect + go.opentelemetry.io/collector/consumer v1.55.0 // indirect + go.opentelemetry.io/collector/consumer/consumererror v0.149.0 // indirect + go.opentelemetry.io/collector/featuregate v1.55.0 // indirect + go.opentelemetry.io/collector/filter v0.149.0 // indirect + go.opentelemetry.io/collector/internal/componentalias v0.149.0 // indirect + go.opentelemetry.io/collector/pipeline v1.55.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect go.opentelemetry.io/otel/sdk v1.42.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.42.0 // indirect - go.opentelemetry.io/otel/trace v1.42.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.49.0 // indirect golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect golang.org/x/net v0.52.0 // indirect golang.org/x/term v0.41.0 // indirect golang.org/x/text v0.35.0 // indirect golang.org/x/tools v0.43.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/tools.sum b/tools.sum index a3d8838f9..06ad6b343 100644 --- a/tools.sum +++ b/tools.sum @@ -38,6 +38,8 @@ codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6M codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= codeberg.org/polyfloyd/go-errorlint v1.9.0 h1:VkdEEmA1VBpH6ecQoMR4LdphVI3fA4RrCh2an7YmodI= codeberg.org/polyfloyd/go-errorlint v1.9.0/go.mod h1:GPRRu2LzVijNn4YkrZYJfatQIdS+TrcK8rL5Xs24qw8= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= dev.gaijin.team/go/golib v0.6.0 h1:v6nnznFTs4bppib/NyU1PQxobwDHwCXXl15P7DV5Zgo= @@ -47,6 +49,8 @@ github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8 github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= github.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ= github.com/Abirdcfly/dupword v0.1.7/go.mod h1:K0DkBeOebJ4VyOICFdppB23Q0YMOgVafM0zYW0n9lF4= +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/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo= github.com/AdminBenni/iota-mixing v1.0.0/go.mod h1:i4+tpAaB+qMVIV9OK3m4/DAynOd5bQFaOu+2AhtBCNY= github.com/AlwxSin/noinlineerr v1.0.5 h1:RUjt63wk1AYWTXtVXbSqemlbVTb23JOSRiNsshj7TbY= @@ -57,6 +61,8 @@ github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksuf github.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II= github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ= github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= +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/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= @@ -65,6 +71,8 @@ github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/MirrexOne/unqueryvet v1.5.4 h1:38QOxShO7JmMWT+eCdDMbcUgGCOeJphVkzzRgyLJgsQ= github.com/MirrexOne/unqueryvet v1.5.4/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU= github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= @@ -96,42 +104,42 @@ github.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTi github.com/ashanbrown/forbidigo/v2 v2.3.0/go.mod h1:5p6VmsG5/1xx3E785W9fouMxIOkvY2rRV9nMdWadd6c= github.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7Ck6QYSaE= github.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY= -github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k= -github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= +github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= -github.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0= -github.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g= -github.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8= -github.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc= +github.com/aws/aws-sdk-go-v2/config v1.32.14 h1:opVIRo/ZbbI8OIqSOKmpFaY7IwfFUOCCXBsUpJOwDdI= +github.com/aws/aws-sdk-go-v2/config v1.32.14/go.mod h1:U4/V0uKxh0Tl5sxmCBZ3AecYny4UNlVmObYjKuuaiOo= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21 h1:SwGMTMLIlvDNyhMteQ6r8IJSBPlRdXX5d4idhIGbkXA= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21/go.mod h1:UUxgWxofmOdAMuqEsSppbDtGKLfR04HGsD0HXzvhI1k= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 h1:rWyie/PxDRIdhNf4DzRk0lvjVOqFJuNnO8WwaIRVxzQ= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22/go.mod h1:zd/JsJ4P7oGfUhXn1VyLqaRZwPmZwg44Jf2dS84Dm3Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12 h1:qtJZ70afD3ISKWnoX3xB0J2otEqu3LqicRcDBqsj0hQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12/go.mod h1:v2pNpJbRNl4vEUWEh5ytQok0zACAKfdmKS51Hotc3pQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20 h1:siU1A6xjUZ2N8zjTHSXFhB9L/2OY8Dqs0xXiLjF30jA= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20/go.mod h1:4TLZCmVJDM3FOu5P5TJP0zOlu9zWgDWU7aUxWbr+rcw= -github.com/aws/aws-sdk-go-v2/service/s3 v1.97.2 h1:MRNiP6nqa20aEl8fQ6PJpEq11b2d40b16sm4WD7QgMU= -github.com/aws/aws-sdk-go-v2/service/s3 v1.97.2/go.mod h1:FrNA56srbsr3WShiaelyWYEo70x80mXnVZ17ZZfbeqg= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 h1:JRaIgADQS/U6uXDqlPiefP32yXTda7Kqfx+LgspooZM= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13/go.mod h1:CEuVn5WqOMilYl+tbccq8+N2ieCy0gVn3OtRb0vBNNM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 h1:ZlvrNcHSFFWURB8avufQq9gFsheUgjVD9536obIknfM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21/go.mod h1:cv3TNhVrssKR0O/xxLJVRfd2oazSnZnkUeTf6ctUwfQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0 h1:foqo/ocQ7WqKwy3FojGtZQJo0FR4vto9qnz9VaumbCo= +github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0/go.mod h1:uoA43SdFwacedBfSgfFSjjCvYe8aYBS7EnU5GZ/YKMM= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 h1:lFd1+ZSEYJZYvv9d6kXzhkZu07si3f+GQ1AaYwa2LUM= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 h1:dzztQ1YmfPrxdrOiuZRMF6fuOwWlWpD2StNLTceKpys= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw= github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -162,6 +170,8 @@ github.com/catenacyber/perfsprint v0.10.1 h1:u7Riei30bk46XsG8nknMhKLXG9BcXz3+3tl github.com/catenacyber/perfsprint v0.10.1/go.mod h1:DJTGsi/Zufpuus6XPGJyKOTMELe347o6akPvWG9Zcsc= github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das= +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/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -188,7 +198,25 @@ github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7Lsp github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo= +github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= +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= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20240122114842-bbd7aa9bf6fb h1:GIzvVQ9UkUlOhSDlqmrQAAAUd6R3E+caIisNEyWXvNE= +github.com/coreos/pkg v0.0.0-20240122114842-bbd7aa9bf6fb/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs= github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88= github.com/daixiang0/gci v0.13.7 h1:+0bG5eK9vlI08J+J/NWGbWPTNiXPG4WhNLJOkSxWITQ= @@ -203,10 +231,18 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +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/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= +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/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/elastic/go-freelru v0.16.0 h1:gG2HJ1WXN2tNl5/p40JS/l59HjvjRhjyAa+oFTRArYs= github.com/elastic/go-freelru v0.16.0/go.mod h1:bSdWT4M0lW79K8QbX6XY2heQYSCqD7THoYf82pT/H3I= github.com/elastic/go-perf v0.0.0-20260224073651-af0ee0c731b7 h1:fGi5uudj7m5O1RgQl+bSZmwlqvuUMEi97X7TzWBOMGk= @@ -221,6 +257,8 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= @@ -248,6 +286,8 @@ 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 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s= github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -278,6 +318,8 @@ github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUW github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godoc-lint/godoc-lint v0.11.2 h1:Bp0FkJWoSdNsBikdNgIcgtaoo+xz6I/Y9s5WSBQUeeM= github.com/godoc-lint/godoc-lint v0.11.2/go.mod h1:iVpGdL1JCikNH2gGeAn3Hh+AgN5Gx/I/cxV+91L41jo= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= @@ -349,6 +391,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -463,8 +506,8 @@ github.com/knadh/koanf/providers/file v1.2.1 h1:bEWbtQwYrA+W2DtdBrQWyXqJaJSG3KrP github.com/knadh/koanf/providers/file v1.2.1/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA= github.com/knadh/koanf/providers/fs v1.0.0 h1:tvn4MrduLgdOSUqqEHULUuIcELXf6xDOpH8GUErpYaY= github.com/knadh/koanf/providers/fs v1.0.0/go.mod h1:FksHET+xXFNDozvj8ZCdom54OnZ6eGKJtC5FhZJKx/8= -github.com/knadh/koanf/v2 v2.3.3 h1:jLJC8XCRfLC7n4F+ZKKdBsbq1bfXTpuFhf4L7t94D94= -github.com/knadh/koanf/v2 v2.3.3/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= +github.com/knadh/koanf/v2 v2.3.4 h1:fnynNSDlujWE+v83hAp8wKr/cdoxHLO0629SN+U8Urc= +github.com/knadh/koanf/v2 v2.3.4/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -497,10 +540,12 @@ github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84Yrj github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww= github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM= github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8= @@ -542,6 +587,24 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +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.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= +github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU= +github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg= +github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= +github.com/moby/moby/client v0.4.0 h1:S+2XegzHQrrvTCvF6s5HFzcrywWQmuVnhOXe2kiWjIw= +github.com/moby/moby/client v0.4.0/go.mod h1:QWPbvWchQbxBNdaLSpoKpCdf5E+WxFAgNHogCWDoa7g= +github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U= +github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -570,6 +633,12 @@ github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/open-telemetry/sig-profiling/tools/profcheck v0.0.0-20260303084341-52f633d434c9 h1:3NStK3r8FVhXbU0qkVz/DpPQlaoLLgLHJOAMKyDX4WM= github.com/open-telemetry/sig-profiling/tools/profcheck v0.0.0-20260303084341-52f633d434c9/go.mod h1:KRO+Rec0+KycN1CrIP/6Pu0xOraPhbahCbL36i8FkfM= +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/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= +github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= @@ -579,6 +648,10 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= +github.com/parca-dev/oomprof v0.1.6 h1:potfd09aphNKqsIF54ZsiddTvksVMjQiaKnczFOsVGM= +github.com/parca-dev/oomprof v0.1.6/go.mod h1:iqI6XrmiNWOa8m2vEIKo+GtQrqbWCMLFpBWuk8RuAPs= +github.com/parca-dev/usdt v0.0.2 h1:bpKQycQ++zV8pwkMaJSxZS07XnEXqO3rkHcLYFJDTl4= +github.com/parca-dev/usdt v0.0.2/go.mod h1:bjh3OTksk+pyP7WsHWlRKWaMSJTUr0gx0piZ/tAv6/w= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -591,6 +664,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/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 v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -649,6 +724,8 @@ github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08/go.mod h1:+XL github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc= +github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -684,8 +761,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/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/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -700,12 +777,18 @@ github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/testcontainers/testcontainers-go v0.42.0 h1:He3IhTzTZOygSXLJPMX7n44XtK+qhjat1nI9cneBbUY= +github.com/testcontainers/testcontainers-go v0.42.0/go.mod h1:vZjdY1YmUA1qEForxOIOazfsrdyORJAbhi0bp8plN30= github.com/tetafro/godot v1.5.4 h1:u1ww+gqpRLiIA16yF2PV1CV1n/X3zhyezbNXC3E14Sg= github.com/tetafro/godot v1.5.4/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= +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/tomarrell/wrapcheck/v2 v2.12.0 h1:H/qQ1aNWz/eeIhxKAFvkfIA+N7YDvq6TWVFL27Of9is= github.com/tomarrell/wrapcheck/v2 v2.12.0/go.mod h1:AQhQuZd0p7b6rfW+vUwHm5OMCGgp63moQ9Qr/0BpIWo= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= @@ -735,6 +818,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 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= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= @@ -760,54 +845,62 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 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/collector/cmd/builder v0.148.0 h1:a8mxjU7wyD1Qh9lj0UEfsNRL1/S1/yRDFuGkHIGlwbk= -go.opentelemetry.io/collector/cmd/builder v0.148.0/go.mod h1:pFwU1tJbcpfD+K37IsTboMQ5jsgPBj8nhtkXpO+1WLE= -go.opentelemetry.io/collector/component v1.54.0 h1:LvtX0Tzz18n44OrUFVk77N1FNsejfWJqztB28hrmDM8= -go.opentelemetry.io/collector/component v1.54.0/go.mod h1:yUMBYsySY/sDcXm8kOzEoZxt+JLdala6hxzSW0npOxY= -go.opentelemetry.io/collector/component/componenttest v0.148.0 h1:tBXJWmy2X6KD8S0QU2YZa2zYBqP+IycSM4iOtwDD2pA= -go.opentelemetry.io/collector/component/componenttest v0.148.0/go.mod h1:1c1+6mZOmI0raoya5vA/X0F+fawEjNS6tCEs5xLATtA= -go.opentelemetry.io/collector/confmap v1.54.0 h1:RUoxQ4uAYHTI57GfHh61D00tTQsXm9T88ozrAiicByc= -go.opentelemetry.io/collector/confmap v1.54.0/go.mod h1:mQxG8bk0IWIt9gbWMvzE+cRkOuCuzbzkNGBq2YJ4wNM= -go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 h1:UW8MX5VlKJf67x4Et7J9kPwP9Rv4VSmJ+UUpgRcb//c= -go.opentelemetry.io/collector/confmap/xconfmap v0.148.0/go.mod h1:4qTMr3V0uSXXac9wVs/UD5fIqRKw5yIl58+Vjsc6RHM= -go.opentelemetry.io/collector/consumer v1.54.0 h1:RGGtUN+GbkV1px3T6XdUHmgJ+ldJ1hAHdesFzW/wgL0= -go.opentelemetry.io/collector/consumer v1.54.0/go.mod h1:1PC6XINTL9DdT1bwvfMdHE72EB4RWU/WcPemUrhqKN8= -go.opentelemetry.io/collector/consumer/consumererror v0.148.0 h1:lKVkNWBeRXG41lHBf5KzA9oErRZifx6qTd9erAFfEkE= -go.opentelemetry.io/collector/consumer/consumererror v0.148.0/go.mod h1:N/UppmtknIdzpEiy3xirH1EiBEBOqKqD77NCyNi2Rbc= -go.opentelemetry.io/collector/consumer/consumertest v0.148.0 h1:ms0HtWMj17tI1Yds0hSuUI5QYpNEqd11AAhwIoUY2HE= -go.opentelemetry.io/collector/consumer/consumertest v0.148.0/go.mod h1:wScw/OzKkf/ZzJn4ToI30OoI1kJiY16WNrcFToXSzK0= -go.opentelemetry.io/collector/consumer/xconsumer v0.148.0 h1:m3b9rY7CLD5Pcge6sSKHIT3OlcPN6xqYsdtVs9oJ528= -go.opentelemetry.io/collector/consumer/xconsumer v0.148.0/go.mod h1:bG+Wz6xmIBl/gHzq1sqvksWXqTLuTX17Wo//zIsdZpw= -go.opentelemetry.io/collector/featuregate v1.54.0 h1:ufo5Hy4Co9pcHVg24hyanm8qFG3TkkYbVyQXPVAbwDc= -go.opentelemetry.io/collector/featuregate v1.54.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g= -go.opentelemetry.io/collector/internal/componentalias v0.148.0 h1:Y6MftNIZSzOr47TTj6A2z2UR3IwbeG46sAQshicGtDg= -go.opentelemetry.io/collector/internal/componentalias v0.148.0/go.mod h1:uwKzfehzwRgHxdHgFXYSBHNBeWSSqsqQYGWr5fk08G0= -go.opentelemetry.io/collector/internal/testutil v0.148.0 h1:3Z9hperte3vSmbBTYeNndoEUICICrNz8hzx+v0FYXBQ= -go.opentelemetry.io/collector/internal/testutil v0.148.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= -go.opentelemetry.io/collector/pdata v1.54.0 h1:3LharKb792cQ3VrUGxd3IcpWwfu3ST+GSTU382jVz1s= -go.opentelemetry.io/collector/pdata v1.54.0/go.mod h1:+MqC3VVOv/EX9YVFUo+mI4F0YmwJ+fXBYwjmu+mRiZ8= -go.opentelemetry.io/collector/pdata/pprofile v0.148.0 h1:MgrNZmqwhZGfiYwcKKtM/iXgTZqqvG5dUphriRXMZHU= -go.opentelemetry.io/collector/pdata/pprofile v0.148.0/go.mod h1:MTTMnZPqWX1S/rBDatU0W19udlycBkWuzVV5qnemHdc= -go.opentelemetry.io/collector/pdata/testdata v0.148.0 h1:yzakPuFgoKK8WcrlhyYHLMLA/kLScQKGsXkIgwieAQ8= -go.opentelemetry.io/collector/pdata/testdata v0.148.0/go.mod h1:2rFvxm8qwd3nlO90FtJw6ZGAjt+bLndxmQuJaMO9kfQ= -go.opentelemetry.io/collector/pipeline v1.54.0 h1:jYlCkdFLITVBdeB+IGS07zXWywEgvT3Ky46vdKKT+Ks= -go.opentelemetry.io/collector/pipeline v1.54.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs= -go.opentelemetry.io/collector/receiver v1.54.0 h1:2e9o+eihZ/nJnzVj5JAcJ+VQ653HcZRiT127qBZRqa8= -go.opentelemetry.io/collector/receiver v1.54.0/go.mod h1:xFZnvYTBjdi9iS/d/UUXzss4h311mLsZliQFQXk4o/k= -go.opentelemetry.io/collector/receiver/receivertest v0.148.0 h1:Fu+B4jCqgZVZmhsKBz3tcgimFryR6TRAK2D5VGLD2Xc= -go.opentelemetry.io/collector/receiver/receivertest v0.148.0/go.mod h1:K8dMDMEggEg6jB688VOHutivOGEEZ20FJGe4jV9RtWU= -go.opentelemetry.io/collector/receiver/xreceiver v0.148.0 h1:u66Zi3udD9RMRiNOsZzsVcUjRwqJEK+5LV76Ry9l3K0= -go.opentelemetry.io/collector/receiver/xreceiver v0.148.0/go.mod h1:jyHxf8SOfH48ZXb32IS3vPbVYDinsLlZYQddyrveqMg= -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/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/collector/cmd/builder v0.149.0 h1:ITeN3IiQT6Kiqc+Mo7M40Uh3B3yVhKOfugEiV9osauQ= +go.opentelemetry.io/collector/cmd/builder v0.149.0/go.mod h1:ElmxpyeQW5fQSZAG5WnLfsKustgglJcI1SPlJRjLQxg= +go.opentelemetry.io/collector/cmd/mdatagen v0.149.0 h1:Mnt8+YZAOZXbdYZX/vv2q1Z6ZWP3SA07Fi2dLhGV3mQ= +go.opentelemetry.io/collector/cmd/mdatagen v0.149.0/go.mod h1:rI0xEeY5MTe813eU8vOAvekGEoit+XMwh8PaA79iD98= +go.opentelemetry.io/collector/component v1.55.0 h1:45nb42/UqPDhRdS8FgGRDybRsWSuvS+r6WC2VTVqIRw= +go.opentelemetry.io/collector/component v1.55.0/go.mod h1:7EpGxVpqFkZ2HidyiE9MLvh4cuKU7ye6i5OtxxiYKps= +go.opentelemetry.io/collector/component/componenttest v0.149.0 h1:7SSYIiLpe84LGfYAp7RCkzYuYLuYVSZVn/K/qsJZgHY= +go.opentelemetry.io/collector/component/componenttest v0.149.0/go.mod h1:8xPU3XMsI+J4vfy87YG1bsCVTeedligKWgBcPEZ0yzw= +go.opentelemetry.io/collector/confmap v1.55.0 h1:pBJbjWfIT3q8cy+eVcHCCYXx984NxOjaGTHqIWsXC1A= +go.opentelemetry.io/collector/confmap v1.55.0/go.mod h1:rSKNE5ztWU6fS0pT8rwACn573r4jJc4QzJyoQzZIVtE= +go.opentelemetry.io/collector/confmap/provider/fileprovider v1.55.0 h1:zSSMElAWM5buXLcbLB+XFXjTDCc9AByo9gkSE+DH+MI= +go.opentelemetry.io/collector/confmap/provider/fileprovider v1.55.0/go.mod h1:FoujmivK7VAABBO61KRCUHpOnDXG/2ayMAe4wWM0m50= +go.opentelemetry.io/collector/confmap/xconfmap v0.149.0 h1:D/WzrxKOKedRztoY/MiAj9z8W0/2unpTCbANFCwvuuY= +go.opentelemetry.io/collector/confmap/xconfmap v0.149.0/go.mod h1:lJ1nHIQbH6L5wnj5vTWGr7RWi5Kib2KX5stAxar13Jo= +go.opentelemetry.io/collector/consumer v1.55.0 h1:7Per8P4J0nlBrFVSXb+nwZ+egiel1BRtggZngyykGsM= +go.opentelemetry.io/collector/consumer v1.55.0/go.mod h1:Qrn5fDp/HpDmUp+l2RGKsdKyOPlgGlaZPKvw/z9FfEc= +go.opentelemetry.io/collector/consumer/consumererror v0.149.0 h1:lXJv8UySfvnISJnCbkxf9ghYRQoWcXC78PxGurdnhKY= +go.opentelemetry.io/collector/consumer/consumererror v0.149.0/go.mod h1:8mZKwHejnZpD0+hjg6T2ZYPzs/Ib8512DMFnx4yaknY= +go.opentelemetry.io/collector/consumer/consumertest v0.149.0 h1:IxOkDInfuUM8mT+rMNGtdUuuDlV9X2VS4WAQ/dZSYqg= +go.opentelemetry.io/collector/consumer/consumertest v0.149.0/go.mod h1:ZMvFzch5IRjYBvj6WPc30HRy19smS0WFBXaOu16Wac0= +go.opentelemetry.io/collector/consumer/xconsumer v0.149.0 h1:2z0wRTDsWqPdcC8xp9HJIAJej+07g4/yJrS0xkJJ4hA= +go.opentelemetry.io/collector/consumer/xconsumer v0.149.0/go.mod h1:AG9w3bk38dq3Rk7C2JGf3jw4ldxR063ujYBm3eiMJ7k= +go.opentelemetry.io/collector/featuregate v1.55.0 h1:s/bE8135+8GZpVlQ9qLXQjvprE9KNOGsLhNkqm+EDEU= +go.opentelemetry.io/collector/featuregate v1.55.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g= +go.opentelemetry.io/collector/filter v0.149.0 h1:Vc8spMswopK7a5xAu9vvUfr4gEehZ/0IK0riyZ9kB2k= +go.opentelemetry.io/collector/filter v0.149.0/go.mod h1:s3HKU8FSUe6PVT9v/BimNUPqR2RTJBxDZXBMTcW+6f4= +go.opentelemetry.io/collector/internal/componentalias v0.149.0 h1:0cH1hCy4vujhnAc6z4baLM0mauFZPfyqF9HtQF6YvGo= +go.opentelemetry.io/collector/internal/componentalias v0.149.0/go.mod h1:8oIpxyFLZECp6O7zFDTGeWw72CQ67C8wb6FqAL9wvCo= +go.opentelemetry.io/collector/internal/testutil v0.149.0 h1:OWfUPO3NFKSaJtz/SBZph/2ENHbr/VbzzlBadKUhm8o= +go.opentelemetry.io/collector/internal/testutil v0.149.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= +go.opentelemetry.io/collector/pdata v1.55.0 h1:WBgye8bo8koUyV9Vmp/r2Q3lgDezdsgfKDQAaM1oT2I= +go.opentelemetry.io/collector/pdata v1.55.0/go.mod h1:6jPrbM4tuliCPACDznjFtxnnHisfKfzwrBVoeuESYuk= +go.opentelemetry.io/collector/pdata/pprofile v0.149.0 h1:4/uI7wsgMnmBZm6Z/VNY6sWnaFN09+Nk3jr7XEmTtOk= +go.opentelemetry.io/collector/pdata/pprofile v0.149.0/go.mod h1:4uprs5wMp4MI1/bcP5mYERfobFxBn+QoeNFQBUSVk/U= +go.opentelemetry.io/collector/pdata/testdata v0.149.0 h1:Y9WCJpr9fvpCGmvh6wK0i+QtOn0OyGXnoOkLfq7xtok= +go.opentelemetry.io/collector/pdata/testdata v0.149.0/go.mod h1:5BscHKM7cy9lzPMpnaIFaTOMI8SI02AsEF4rH3aRJBg= +go.opentelemetry.io/collector/pipeline v1.55.0 h1:jxFicLy3QYWQaQZp2f+wdCfHpOYb3mKNTqHR1KIut+U= +go.opentelemetry.io/collector/pipeline v1.55.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs= +go.opentelemetry.io/collector/receiver v1.55.0 h1:7GVQOPleD60LzxvkqHaChlbWw5nJvw6i2fV6UBL+7EQ= +go.opentelemetry.io/collector/receiver v1.55.0/go.mod h1:Sdx1R+nh6p9lQSZJk8KfQK4nzLI4zNrceIk7a8WpSQg= +go.opentelemetry.io/collector/receiver/receivertest v0.149.0 h1:S33+mAxh7QTxY2o0fTFKEN/ULgcuw36hUVQDyIlSpTc= +go.opentelemetry.io/collector/receiver/receivertest v0.149.0/go.mod h1:w+W/7Dd64jHeCsQcJZBB6oSz3gasvKz5KP1yKzaN8V8= +go.opentelemetry.io/collector/receiver/xreceiver v0.149.0 h1:EpJ5zqTrJwQT1QsX+JHRcDfTA1Mzf0gAOPGihkxtn7E= +go.opentelemetry.io/collector/receiver/xreceiver v0.149.0/go.mod h1:hoUUGXcIr7ZuDdkqzLGfy5P7Njsc/YQ8riWX70Ukf6E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= 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/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 h1:ZQs05qo3Yh4KUHeVH6v89xErwmsvgA/cLX2/w5Ikp+k= @@ -839,6 +932,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= 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= @@ -964,6 +1059,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w 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= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -986,12 +1082,14 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1087,8 +1185,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= 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= @@ -1140,8 +1238,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +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.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= @@ -1155,8 +1253,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1209,6 +1307,8 @@ mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= mvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s= mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 h1:ssMzja7PDPJV8FStj7hq9IKiuiKhgz9ErWw+m68e7DI= mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15/go.mod h1:4M5MMXl2kW6fivUT6yRGpLLPNfuGtU2Z0cPvFquGDYU= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= 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= diff --git a/tools/coredump/new.go b/tools/coredump/new.go index 73b382d82..3df9499f3 100644 --- a/tools/coredump/new.go +++ b/tools/coredump/new.go @@ -60,7 +60,7 @@ func newTrackedCoredump(corePath, filePrefix string) (*trackedCoredump, error) { }, nil } -func (tc *trackedCoredump) GetMappingFileLastModified(_ *process.Mapping) int64 { +func (tc *trackedCoredump) GetMappingFileLastModified(_ *process.RawMapping) int64 { return 0 } @@ -71,9 +71,9 @@ func (tc *trackedCoredump) warnMissing(fileName string) { } } -func (tc *trackedCoredump) CalculateMappingFileID(m *process.Mapping) (libpf.FileID, error) { +func (tc *trackedCoredump) CalculateMappingFileID(m *process.RawMapping) (libpf.FileID, error) { if !m.IsVDSO() && !m.IsAnonymous() { - file := m.Path.String() + file := m.Path fid, err := libpf.FileIDFromExecutableFile(path.Join(tc.prefix, file)) if err == nil { tc.seen[file] = libpf.Void{} @@ -84,9 +84,9 @@ func (tc *trackedCoredump) CalculateMappingFileID(m *process.Mapping) (libpf.Fil return tc.CoredumpProcess.CalculateMappingFileID(m) } -func (tc *trackedCoredump) OpenMappingFile(m *process.Mapping) (process.ReadAtCloser, error) { +func (tc *trackedCoredump) OpenMappingFile(m *process.RawMapping) (process.ReadAtCloser, error) { if !m.IsVDSO() && !m.IsAnonymous() { - file := m.Path.String() + file := m.Path rac, err := os.Open(path.Join(tc.prefix, file)) if err == nil { tc.seen[file] = libpf.Void{} @@ -98,7 +98,7 @@ func (tc *trackedCoredump) OpenMappingFile(m *process.Mapping) (process.ReadAtCl } func (tc *trackedCoredump) OpenELF(fileName string) (*pfelf.File, error) { - if fileName != process.VdsoPathName.String() { + if fileName != process.VdsoPathName { f, err := pfelf.Open(path.Join(tc.prefix, fileName)) if err == nil { tc.seen[fileName] = libpf.Void{} diff --git a/tools/coredump/storecoredump.go b/tools/coredump/storecoredump.go index 954c700a1..b1ecef55d 100644 --- a/tools/coredump/storecoredump.go +++ b/tools/coredump/storecoredump.go @@ -45,8 +45,8 @@ func (scd *StoreCoredump) openFile(path string) (process.ReadAtCloser, error) { return file, nil } -func (scd *StoreCoredump) OpenMappingFile(m *process.Mapping) (process.ReadAtCloser, error) { - return scd.openFile(m.Path.String()) +func (scd *StoreCoredump) OpenMappingFile(m *process.RawMapping) (process.ReadAtCloser, error) { + return scd.openFile(m.Path) } func (scd *StoreCoredump) OpenELF(path string) (*pfelf.File, error) { diff --git a/tools/probe-ctrl/go.mod b/tools/probe-ctrl/go.mod index 4a2ff937e..4babde11e 100644 --- a/tools/probe-ctrl/go.mod +++ b/tools/probe-ctrl/go.mod @@ -11,7 +11,7 @@ replace go.opentelemetry.io/ebpf-profiler => ../../ require ( github.com/cilium/ebpf v0.21.0 - go.opentelemetry.io/ebpf-profiler v0.0.202610 + go.opentelemetry.io/ebpf-profiler v0.0.202614 ) require ( @@ -32,27 +32,27 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/zeebo/xxh3 v1.1.0 // indirect - go.opentelemetry.io/collector/consumer v1.53.0 // indirect - go.opentelemetry.io/collector/consumer/xconsumer v0.147.0 // indirect - go.opentelemetry.io/collector/featuregate v1.53.0 // indirect - go.opentelemetry.io/collector/pdata v1.53.0 // indirect - go.opentelemetry.io/collector/pdata/pprofile v0.147.0 // indirect - go.opentelemetry.io/otel v1.42.0 // indirect - go.opentelemetry.io/otel/metric v1.42.0 // indirect + go.opentelemetry.io/collector/consumer v1.55.0 // indirect + go.opentelemetry.io/collector/consumer/xconsumer v0.149.0 // indirect + go.opentelemetry.io/collector/featuregate v1.55.0 // indirect + go.opentelemetry.io/collector/pdata v1.55.0 // indirect + go.opentelemetry.io/collector/pdata/pprofile v0.149.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.25.0 // indirect - golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect + golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.51.0 // indirect + golang.org/x/mod v0.34.0 // indirect + golang.org/x/net v0.52.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.42.0 // indirect - golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.0 // indirect + golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c // indirect + golang.org/x/text v0.35.0 // indirect + golang.org/x/tools v0.43.0 // indirect golang.org/x/vuln v1.1.4 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect - google.golang.org/grpc v1.79.2 // indirect + google.golang.org/grpc v1.80.0 // indirect google.golang.org/protobuf v1.36.11 // indirect honnef.co/go/tools v0.7.0 // indirect ) diff --git a/tools/probe-ctrl/go.sum b/tools/probe-ctrl/go.sum index 5cb23d290..a22da2263 100644 --- a/tools/probe-ctrl/go.sum +++ b/tools/probe-ctrl/go.sum @@ -84,38 +84,38 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= 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/collector/consumer v1.53.0 h1:Gyy80dX5r1Lv9lvQk8XFtUkWs1eniicOzzCQBejLseg= -go.opentelemetry.io/collector/consumer v1.53.0/go.mod h1:f5U6ibd+XpC5eOSeEYhERAQJ2a5bp1d2RzW3MFddMDM= -go.opentelemetry.io/collector/consumer/xconsumer v0.147.0 h1:XJVQc2dYyalaFXMTa4/RE+aweQTiBpw1edfwdCIJSxw= -go.opentelemetry.io/collector/consumer/xconsumer v0.147.0/go.mod h1:mtwh1VsUoGjxwdmXEzjbswH7KAGByJNCIMHmhqwXeK0= -go.opentelemetry.io/collector/featuregate v1.53.0 h1:cgjXdtl7jezWxq6V0eohe/JqjY4PBotZGb5+bTR2OJw= -go.opentelemetry.io/collector/featuregate v1.53.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g= -go.opentelemetry.io/collector/internal/testutil v0.147.0 h1:DFlRxBRp23/sZnpTITK25yqe0d56yNvK+63IaWc6OsU= -go.opentelemetry.io/collector/internal/testutil v0.147.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= -go.opentelemetry.io/collector/pdata v1.53.0 h1:DlYDbRwammEZaxDZHINx5v0n8SEOVNniPbi6FRTlVkA= -go.opentelemetry.io/collector/pdata v1.53.0/go.mod h1:LRSYGNjKXaUrZEwZv3Yl+8/zV2HmRGKXW62zB2bysms= -go.opentelemetry.io/collector/pdata/pprofile v0.147.0 h1:yQS3RBvcvRcy9N7AnJvsxmse0AxJcRqBZfwMA22xBA8= -go.opentelemetry.io/collector/pdata/pprofile v0.147.0/go.mod h1:pm9mUqHNpT1SaCkxILu4FW1BvMAelh7EKhpSKe2KJIQ= -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/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.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= -go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= +go.opentelemetry.io/collector/consumer v1.55.0 h1:7Per8P4J0nlBrFVSXb+nwZ+egiel1BRtggZngyykGsM= +go.opentelemetry.io/collector/consumer v1.55.0/go.mod h1:Qrn5fDp/HpDmUp+l2RGKsdKyOPlgGlaZPKvw/z9FfEc= +go.opentelemetry.io/collector/consumer/xconsumer v0.149.0 h1:2z0wRTDsWqPdcC8xp9HJIAJej+07g4/yJrS0xkJJ4hA= +go.opentelemetry.io/collector/consumer/xconsumer v0.149.0/go.mod h1:AG9w3bk38dq3Rk7C2JGf3jw4ldxR063ujYBm3eiMJ7k= +go.opentelemetry.io/collector/featuregate v1.55.0 h1:s/bE8135+8GZpVlQ9qLXQjvprE9KNOGsLhNkqm+EDEU= +go.opentelemetry.io/collector/featuregate v1.55.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g= +go.opentelemetry.io/collector/internal/testutil v0.149.0 h1:OWfUPO3NFKSaJtz/SBZph/2ENHbr/VbzzlBadKUhm8o= +go.opentelemetry.io/collector/internal/testutil v0.149.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= +go.opentelemetry.io/collector/pdata v1.55.0 h1:WBgye8bo8koUyV9Vmp/r2Q3lgDezdsgfKDQAaM1oT2I= +go.opentelemetry.io/collector/pdata v1.55.0/go.mod h1:6jPrbM4tuliCPACDznjFtxnnHisfKfzwrBVoeuESYuk= +go.opentelemetry.io/collector/pdata/pprofile v0.149.0 h1:4/uI7wsgMnmBZm6Z/VNY6sWnaFN09+Nk3jr7XEmTtOk= +go.opentelemetry.io/collector/pdata/pprofile v0.149.0/go.mod h1:4uprs5wMp4MI1/bcP5mYERfobFxBn+QoeNFQBUSVk/U= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= +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.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 h1:ZQs05qo3Yh4KUHeVH6v89xErwmsvgA/cLX2/w5Ikp+k= go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0/go.mod h1:3iiRVKaCfVo0UI1ZaSMm5WbCBbINRqVlD9SUmvyBNrY= -go.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE= -go.opentelemetry.io/proto/slim/otlp v1.9.0/go.mod h1:xXdeJJ90Gqyll+orzUkY4bOd2HECo5JofeoLpymVqdI= -go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 h1:o13nadWDNkH/quoDomDUClnQBpdQQ2Qqv0lQBjIXjE8= -go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0/go.mod h1:Gyb6Xe7FTi/6xBHwMmngGoHqL0w29Y4eW8TGFzpefGA= -go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0 h1:EiUYvtwu6PMrMHVjcPfnsG3v+ajPkbUeH+IL93+QYyk= -go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0/go.mod h1:mUUHKFiN2SST3AhJ8XhJxEoeVW12oqfXog0Bo8W3Ec4= +go.opentelemetry.io/proto/slim/otlp v1.10.0 h1:iR97Vs/ZDR+y9TfuP9b1XBtdPWeC+OMslIBmhcLU7jM= +go.opentelemetry.io/proto/slim/otlp v1.10.0/go.mod h1:lV9250stpjYLPNA5viFabIgP2QlUGRT1GdTgAf8SIUk= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.3.0 h1:RUF5rO0hAlgiJt1fzQVzcVs3vZVNHIcMLgOgG4rWNcQ= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.3.0/go.mod h1:I89cynRj8y+383o7tEQVg2SVA6SRgDVIouWPUVXjx0U= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.3.0 h1:CQvJSldHRUN6Z8jsUeYv8J0lXRvygALXIzsmAeCcZE0= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.3.0/go.mod h1:xSQ+mEfJe/GjK1LXEyVOoSI1N9JV9ZI923X5kup43W4= 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= @@ -123,18 +123,18 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE= golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ= golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/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.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= -golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -145,13 +145,13 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c h1:6a8FdnNk6bTXBjR4AGKFgUKuo+7GnR3FX5L7CbveeZc= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -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/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -159,12 +159,12 @@ golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGN golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -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/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/tracer/events.go b/tracer/events.go index 56c608f30..f87eeccb1 100644 --- a/tracer/events.go +++ b/tracer/events.go @@ -35,6 +35,10 @@ const ( // events are produced by the kernel between two polling intervals, the queue from bpf // to userspace will fill up and the kernel will start dropping events. maxEvents = 4096 + + // eventReaderDeadline is the timeout for perf event reads. It allows the + // reader goroutine to periodically check for context cancellation. + eventReaderDeadline = 100 * time.Millisecond ) // StartPIDEventProcessor spawns a goroutine to process PID events. @@ -100,28 +104,36 @@ func startPerfEventMonitor(ctx context.Context, perfEventMap *ebpf.Map, return nil, fmt.Errorf("Failed to setup perf reporting via %s: %v", perfEventMap, err) } + // Set a deadline so ReadInto times out periodically and we can check context + eventReader.SetDeadline(time.Now().Add(eventReaderDeadline)) + var lostEventsCount, readErrorCount, noDataCount atomic.Uint64 go func() { + defer eventReader.Close() var data perf.Record for { select { case <-ctx.Done(): return default: - if err := eventReader.ReadInto(&data); err != nil { + } + // Set a deadline so ReadInto times out and we can check context + eventReader.SetDeadline(time.Now().Add(eventReaderDeadline)) + if err := eventReader.ReadInto(&data); err != nil { + if !errors.Is(err, os.ErrDeadlineExceeded) { readErrorCount.Add(1) - continue - } - if data.LostSamples != 0 { - lostEventsCount.Add(data.LostSamples) - continue } - if len(data.RawSample) == 0 { - noDataCount.Add(1) - continue - } - triggerFunc(data.RawSample) + continue + } + if data.LostSamples != 0 { + lostEventsCount.Add(data.LostSamples) + continue + } + if len(data.RawSample) == 0 { + noDataCount.Add(1) + continue } + triggerFunc(data.RawSample) } }() @@ -160,6 +172,7 @@ func (t *Tracer) startTraceEventMonitor(ctx context.Context, var lostEventsCount, readErrorCount, noDataCount atomic.Uint64 go func() { + defer eventReader.Close() var data perf.Record var oldKTime, minKTime int64 var eventCount int diff --git a/tracer/tracer.go b/tracer/tracer.go index 8270b2130..73db3bab3 100644 --- a/tracer/tracer.go +++ b/tracer/tracer.go @@ -98,10 +98,6 @@ type Tracer struct { // tracePool is cache of libpf.EbpfTrace to avoid GC pressure tracePool sync.Pool - // monitorPIDEventsMap iterates over the eBPF map pid_events, collects PIDs and - // writes them to the keys slice. The implementation is selected on creation. - monitorPIDEventsMapMethod func(keys *[]libpf.PIDTID) error - // triggerPIDProcessing is used as manual trigger channel to request immediate // processing of pending PIDs. This is requested on notifications from eBPF code // when process events take place (new, exit, unknown PC). @@ -116,8 +112,6 @@ type Tracer struct { // intervals provides access to globally configured timers and counters. intervals Intervals - hasBatchOperations bool - // samplesPerSecond holds the configured number of samples per second. samplesPerSecond int @@ -260,9 +254,6 @@ func NewTracer(ctx context.Context, cfg *Config) (*Tracer, error) { return nil, fmt.Errorf("failed to load eBPF maps: %v", err) } - hasBatchOperations := ebpfHandler.SupportsGenericBatchOperations() - hasBatchLookupAndDelete := ebpfHandler.SupportsGenericBatchLookupAndDelete() - processManager, err := pm.New(ctx, cfg.IncludeTracers, cfg.Intervals.MonitorInterval(), cfg.Intervals.ExecutableUnloadDelay(), ebpfHandler, cfg.TraceReporter, cfg.ExecutableReporter, elfunwindinfo.NewStackDeltaProvider(), @@ -283,7 +274,6 @@ func NewTracer(ctx context.Context, cfg *Config) (*Tracer, error) { ebpfProgs: ebpfProgs, hooks: make(map[hookPoint]link.Link), intervals: cfg.Intervals, - hasBatchOperations: hasBatchOperations, perfEntrypoints: xsync.NewRWMutex(perfEventList), samplesPerSecond: cfg.SamplesPerSecond, traceBufferSizeMultiplier: cfg.TraceBufferSizeMultiplier, @@ -292,13 +282,6 @@ func NewTracer(ctx context.Context, cfg *Config) (*Tracer, error) { done: make(chan libpf.Void), } - // Use an optimized version if available - if hasBatchLookupAndDelete { - tracer.monitorPIDEventsMapMethod = (*tracer).monitorPIDEventsMapBatch - } else { - tracer.monitorPIDEventsMapMethod = (*tracer).monitorPIDEventsMapSingle - } - return tracer, nil } @@ -885,72 +868,9 @@ func (t *Tracer) enableEvent(eventType int) { _ = inhibitEventsMap.Delete(unsafe.Pointer(&et)) } -// monitorPIDEventsMapSingle iterates over the eBPF map pid_events, collects PIDs -// and writes them to the keys slice. -func (t *Tracer) monitorPIDEventsMapSingle(keys *[]libpf.PIDTID) error { - eventsMap := t.ebpfMaps["pid_events"] - var key, nextKey uint64 - var value bool - keyFound := true - deleteBatch := make(libpf.Set[uint64]) - - // Key 0 retrieves the very first element in the hash map as - // it is guaranteed not to exist in pid_events. - key = 0 - if err := eventsMap.NextKey(unsafe.Pointer(&key), unsafe.Pointer(&nextKey)); err != nil { - if errors.Is(err, cebpf.ErrKeyNotExist) { - return nil - } - return fmt.Errorf("Failed to read from pid_events map: %v", err) - } - - for keyFound { - key = nextKey - - if err := eventsMap.Lookup(unsafe.Pointer(&key), unsafe.Pointer(&value)); err != nil { - return fmt.Errorf("Failed to lookup '%v' in pid_events: %v", key, err) - } - - // Lookup the next map entry before deleting the current one. - if err := eventsMap.NextKey(unsafe.Pointer(&key), unsafe.Pointer(&nextKey)); err != nil { - if !errors.Is(err, cebpf.ErrKeyNotExist) { - return fmt.Errorf("Failed to read from pid_events map: %v", err) - } - keyFound = false - } - - if !t.hasBatchOperations { - // Now that we have the next key, we can delete the current one. - if err := eventsMap.Delete(unsafe.Pointer(&key)); err != nil { - return fmt.Errorf("Failed to delete '%v' from pid_events: %v", key, err) - } - } else { - // Store to-be-deleted keys in a map so we can delete them all with a single - // bpf syscall. - deleteBatch[key] = libpf.Void{} - } - - // If we process keys inline with iteration (e.g. by sending them to t.pidEvents at this - // exact point), we may block sending to the channel, delay the iteration and may introduce - // race conditions (related to deletion). For that reason, keys are first collected and, - // after the iteration has finished, sent to the channel. - *keys = append(*keys, libpf.PIDTID(key)) - } - - keysToDelete := len(deleteBatch) - if keysToDelete != 0 { - keys := libpf.MapKeysToSlice(deleteBatch) - if _, err := eventsMap.BatchDelete(keys, nil); err != nil { - return fmt.Errorf("Failed to batch delete %d entries from pid_events map: %v", - keysToDelete, err) - } - } - return nil -} - -// monitorPIDEventsMapBatch iterates over the eBPF map pid_events in batches, +// monitorPIDEventsMap iterates over the eBPF map pid_events in batches, // collects PIDs and writes them to the keys slice. -func (t *Tracer) monitorPIDEventsMapBatch(keys *[]libpf.PIDTID) error { +func (t *Tracer) monitorPIDEventsMap(keys *[]libpf.PIDTID) error { eventsMap := t.ebpfMaps["pid_events"] removed := make([]uint64, 128) @@ -1131,7 +1051,7 @@ func (t *Tracer) StartMapMonitors(ctx context.Context, traceOutChan chan<- *libp periodiccaller.StartWithManualTrigger(ctx, t.intervals.MonitorInterval(), t.triggerPIDProcessing, func(_ bool) bool { t.enableEvent(support.EventTypeGenericPID) - err := t.monitorPIDEventsMapMethod(&pidEvents) + err := t.monitorPIDEventsMap(&pidEvents) if err != nil { log.Errorf("Failed to monitor PID events: %v", err) t.signalDone()