From 0514a283ce30a2049c5a1789c0286bee560515ea Mon Sep 17 00:00:00 2001 From: Alex Lew Date: Fri, 21 Feb 2025 13:09:19 -0800 Subject: [PATCH 1/3] feat: add cumulativetodelta processor --- README.md | 11 +- builder-config.yaml | 1 + go.mod | 1 + observecol/components.go | 3 + observecol/go.mod | 1 + .../cumulativetodeltaprocessor/LICENSE | 201 ++++++++++++++ .../cumulativetodeltaprocessor/Makefile | 1 + .../cumulativetodeltaprocessor/README.md | 99 +++++++ .../cumulativetodeltaprocessor/config.go | 56 ++++ .../cumulativetodeltaprocessor/doc.go | 8 + .../cumulativetodeltaprocessor/factory.go | 53 ++++ .../internal/metadata/generated_status.go | 16 ++ .../internal/tracking/identity.go | 75 ++++++ .../internal/tracking/metric.go | 9 + .../internal/tracking/tracker.go | 245 ++++++++++++++++++ .../internal/tracking/value.go | 30 +++ .../cumulativetodeltaprocessor/metadata.yaml | 12 + .../cumulativetodeltaprocessor/processor.go | 202 +++++++++++++++ vendor/modules.txt | 5 + 19 files changed, 1024 insertions(+), 5 deletions(-) create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/LICENSE create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/Makefile create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/README.md create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/config.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/doc.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/factory.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/metadata/generated_status.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/identity.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/metric.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/tracker.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/value.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/metadata.yaml create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/processor.go diff --git a/README.md b/README.md index b0801f52c..bfd2c4cd4 100644 --- a/README.md +++ b/README.md @@ -70,11 +70,11 @@ This section lists the components that are included in the Observe Distribution |----------------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------|--------------------------------------|-----------------------------| | [awsecscontainermetrics][awsecscontainermetricsreceiver] | [attributes][attributesprocessor] | [debug][debugexporter] | [file_storage][filestorage] | [count][countconnector] | | [docker_stats][dockerstatsreceiver] | [batch][batchprocessor] | [file][fileexporter] | [health_check][healthcheckextension] | [forward][forwardconnector] | -| [elasticsearch][elasticsearchreceiver] | [deltatocumulative][deltatocumulativeprocessor] | [otlphttp][otlphttpexporter] | [zpages][zpagesextension] | | -| [filelog][filelogreceiver] | [filter][filterprocessor] | [prometheusremotewrite][prometheusremotewriteexporter] | | | -| [filestats][filestatsreceiver] | [k8sattributes][k8sattributesprocessor] | | | | -| [hostmetrics][hostmetricsreceiver] | [memory_limiter][memorylimiterprocessor] | | | | -| [httpcheck][httpcheckreceiver] | | | | | +| [elasticsearch][elasticsearchreceiver] | [cumulativetodelta][cumulativetodeltaprocessor] | [otlphttp][otlphttpexporter] | [zpages][zpagesextension] | | +| [filelog][filelogreceiver] | [deltatocumulative][deltatocumulativeprocessor] | [prometheusremotewrite][prometheusremotewriteexporter] | | | +| [filestats][filestatsreceiver] | [filter][filterprocessor] | | | | +| [hostmetrics][hostmetricsreceiver] | [k8sattributes][k8sattributesprocessor] | | | | +| [httpcheck][httpcheckreceiver] | [memory_limiter][memorylimiterprocessor] | | | | | [iis][iisreceiver] | [observek8sattributes][observek8sattributesprocessor] | | | | | [journald][journaldreceiver] | [probabilisticsampler][probabilisticsamplerprocessor] | | | | | [k8s_cluster][k8sclusterreceiver] | [redaction][redactionprocessor] | | | | @@ -117,6 +117,7 @@ This section lists the components that are included in the Observe Distribution [windowseventlogreceiver]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/receiver/windowseventlogreceiver [attributesprocessor]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/processor/attributesprocessor [batchprocessor]: https://github.com/open-telemetry/opentelemetry-collector/tree/v0.118.0/processor/batchprocessor +[cumulativetodeltaprocessor]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/processor/cumulativetodeltaprocessor [deltatocumulativeprocessor]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/processor/deltatocumulativeprocessor [filterprocessor]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/processor/filterprocessor [k8sattributesprocessor]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/processor/k8sattributesprocessor diff --git a/builder-config.yaml b/builder-config.yaml index 6f99a4476..32d8a82db 100644 --- a/builder-config.yaml +++ b/builder-config.yaml @@ -17,6 +17,7 @@ processors: - gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.118.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.118.0 + - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor v0.118.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.118.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor v0.118.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor v0.118.0 diff --git a/go.mod b/go.mod index 1eba9cb06..4d7789ba7 100644 --- a/go.mod +++ b/go.mod @@ -205,6 +205,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/pkg/winperfcounters v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.118.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor v0.118.0 // indirect diff --git a/observecol/components.go b/observecol/components.go index d7ec626c0..642b3a08b 100644 --- a/observecol/components.go +++ b/observecol/components.go @@ -22,6 +22,7 @@ import ( batchprocessor "go.opentelemetry.io/collector/processor/batchprocessor" memorylimiterprocessor "go.opentelemetry.io/collector/processor/memorylimiterprocessor" attributesprocessor "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor" + cumulativetodeltaprocessor "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor" deltatocumulativeprocessor "github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor" filterprocessor "github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor" k8sattributesprocessor "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor" @@ -147,6 +148,7 @@ func components() (otelcol.Factories, error) { batchprocessor.NewFactory(), memorylimiterprocessor.NewFactory(), attributesprocessor.NewFactory(), + cumulativetodeltaprocessor.NewFactory(), deltatocumulativeprocessor.NewFactory(), filterprocessor.NewFactory(), k8sattributesprocessor.NewFactory(), @@ -166,6 +168,7 @@ func components() (otelcol.Factories, error) { factories.ProcessorModules[batchprocessor.NewFactory().Type()] = "go.opentelemetry.io/collector/processor/batchprocessor v0.118.0" factories.ProcessorModules[memorylimiterprocessor.NewFactory().Type()] = "go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.118.0" factories.ProcessorModules[attributesprocessor.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.118.0" + factories.ProcessorModules[cumulativetodeltaprocessor.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor v0.118.0" factories.ProcessorModules[deltatocumulativeprocessor.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.118.0" factories.ProcessorModules[filterprocessor.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor v0.118.0" factories.ProcessorModules[k8sattributesprocessor.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor v0.118.0" diff --git a/observecol/go.mod b/observecol/go.mod index 35a48be79..0c7810ffe 100644 --- a/observecol/go.mod +++ b/observecol/go.mod @@ -13,6 +13,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.118.0 + github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor v0.118.0 diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/LICENSE b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/Makefile b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/Makefile new file mode 100644 index 000000000..c1496226e --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common \ No newline at end of file diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/README.md b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/README.md new file mode 100644 index 000000000..6963e4700 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/README.md @@ -0,0 +1,99 @@ +# Cumulative to Delta Processor + +| Status | | +| ------------- |-----------| +| Stability | [beta]: metrics | +| Distributions | [contrib], [k8s] | +| Warnings | [Statefulness](#warnings) | +| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aprocessor%2Fcumulativetodelta%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aprocessor%2Fcumulativetodelta) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aprocessor%2Fcumulativetodelta%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aprocessor%2Fcumulativetodelta) | +| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@TylerHelmuth](https://www.github.com/TylerHelmuth) | + +[beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta +[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib +[k8s]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-k8s + + +## Description + +The cumulative to delta processor (`cumulativetodeltaprocessor`) converts monotonic, cumulative sum and histogram metrics to monotonic, delta metrics. Non-monotonic sums and exponential histograms are excluded. + +## Configuration + +Configuration is specified through a list of metrics. The processor uses metric names to identify a set of cumulative metrics and converts them from cumulative to delta. + +The following settings can be optionally configured: + +- `include`: List of metrics names or patterns to convert to delta. +- `exclude`: List of metrics names or patterns to not convert to delta. **If a metric name matches both include and exclude, exclude takes precedence.** +- `max_staleness`: The total time a state entry will live past the time it was last seen. Set to 0 to retain state indefinitely. Default: 0 +- `initial_value`: Handling of the first observed point for a given metric identity. + When the collector (re)starts, there's no record of how much of a given cumulative counter has already been converted to delta values. + - `auto` (default): Send if and only if the startime is set AND the starttime happens after the component started AND the starttime is different from the timestamp. + Suitable for gateway deployments, this heuristic is like `drop`, but keeps values for newly started counters (which could not have had previous observed values). + - `keep`: Send the observed value as the delta value. + Suitable for when the incoming metrics have not been observed before, + e.g. running the collector as a sidecar, the collector lifecycle is tied to the metric source. + - `drop`: Keep the observed value but don't send. + Suitable for gateway deployments, guarantees that all delta counts it produces haven't been observed before, but loses the values between thir first 2 observations. + +If neither include nor exclude are supplied, no filtering is applied. + +#### Examples + +```yaml +processors: + # processor name: cumulativetodelta + cumulativetodelta: + + # list the exact cumulative sum or histogram metrics to convert to delta + include: + metrics: + - + - + . + . + - + match_type: strict +``` + +```yaml +processors: + # processor name: cumulativetodelta + cumulativetodelta: + + # Convert cumulative sum or histogram metrics to delta + # if and only if 'metric' is in the name + include: + metrics: + - ".*metric.*" + match_type: regexp +``` + +```yaml +processors: + # processor name: cumulativetodelta + cumulativetodelta: + + # Convert cumulative sum or histogram metrics to delta + # if and only if 'metric' is not in the name + exclude: + metrics: + - ".*metric.*" + match_type: regexp +``` + +```yaml +processors: + # processor name: cumulativetodelta + cumulativetodelta: + # If include/exclude are not specified + # convert all cumulative sum or histogram metrics to delta +``` + +## Warnings + +- [Statefulness](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/standard-warnings.md#statefulness): The cumulativetodelta processor's calculates delta by remembering the previous value of a metric. For this reason, the calculation is only accurate if the metric is continuously sent to the same instance of the collector. As a result, the cumulativetodelta processor may not work as expected if used in a deployment of multiple collectors. When using this processor it is best for the data source to being sending data to a single collector. + + +[beta]: https://github.com/open-telemetry/opentelemetry-collector#beta +[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/config.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/config.go new file mode 100644 index 000000000..dcba656c8 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/config.go @@ -0,0 +1,56 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package cumulativetodeltaprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor" + +import ( + "fmt" + "time" + + "go.opentelemetry.io/collector/component" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterset" + "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking" +) + +// Config defines the configuration for the processor. +type Config struct { + // MaxStaleness is the total time a state entry will live past the time it was last seen. Set to 0 to retain state indefinitely. + MaxStaleness time.Duration `mapstructure:"max_staleness"` + + // InitialValue determines how to handle the first datapoint for a given metric. Valid values: + // + // - auto: (default) send the first point iff the startime is set AND the starttime happens after the component started AND the starttime is different from the timestamp + // - keep: always send the first point + // - drop: don't send the first point, but store it for subsequent delta calculations + InitialValue tracking.InitialValue `mapstructure:"initial_value"` + + // Include specifies a filter on the metrics that should be converted. + // Exclude specifies a filter on the metrics that should not be converted. + // If neither `include` nor `exclude` are set, all metrics will be converted. + // Cannot be used with deprecated Metrics config option. + Include MatchMetrics `mapstructure:"include"` + Exclude MatchMetrics `mapstructure:"exclude"` +} + +type MatchMetrics struct { + filterset.Config `mapstructure:",squash"` + + Metrics []string `mapstructure:"metrics"` +} + +var _ component.Config = (*Config)(nil) + +// Validate checks whether the input configuration has all of the required fields for the processor. +// An error is returned if there are any invalid inputs. +func (config *Config) Validate() error { + if (len(config.Include.Metrics) > 0 && len(config.Include.MatchType) == 0) || + (len(config.Exclude.Metrics) > 0 && len(config.Exclude.MatchType) == 0) { + return fmt.Errorf("match_type must be set if metrics are supplied") + } + if (len(config.Include.MatchType) > 0 && len(config.Include.Metrics) == 0) || + (len(config.Exclude.MatchType) > 0 && len(config.Exclude.Metrics) == 0) { + return fmt.Errorf("metrics must be supplied if match_type is set") + } + return nil +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/doc.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/doc.go new file mode 100644 index 000000000..121644be7 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/doc.go @@ -0,0 +1,8 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:generate mdatagen metadata.yaml + +// package cumulativetodeltaprocessor implements a processor which +// converts cumulative sum metrics to cumulative delta. +package cumulativetodeltaprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor" diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/factory.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/factory.go new file mode 100644 index 000000000..24ffc9c3e --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/factory.go @@ -0,0 +1,53 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package cumulativetodeltaprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor" + +import ( + "context" + "fmt" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/processor/processorhelper" + + "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/metadata" +) + +var processorCapabilities = consumer.Capabilities{MutatesData: true} + +// NewFactory returns a new factory for the Metrics Generation processor. +func NewFactory() processor.Factory { + return processor.NewFactory( + metadata.Type, + createDefaultConfig, + processor.WithMetrics(createMetricsProcessor, metadata.MetricsStability)) +} + +func createDefaultConfig() component.Config { + return &Config{} +} + +func createMetricsProcessor( + ctx context.Context, + set processor.Settings, + cfg component.Config, + nextConsumer consumer.Metrics, +) (processor.Metrics, error) { + processorConfig, ok := cfg.(*Config) + if !ok { + return nil, fmt.Errorf("configuration parsing error") + } + + metricsProcessor := newCumulativeToDeltaProcessor(processorConfig, set.Logger) + + return processorhelper.NewMetrics( + ctx, + set, + cfg, + nextConsumer, + metricsProcessor.processMetrics, + processorhelper.WithCapabilities(processorCapabilities), + processorhelper.WithShutdown(metricsProcessor.shutdown)) +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/metadata/generated_status.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/metadata/generated_status.go new file mode 100644 index 000000000..093893af7 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/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("cumulativetodelta") + ScopeName = "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor" +) + +const ( + MetricsStability = component.StabilityLevelBeta +) diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/identity.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/identity.go new file mode 100644 index 000000000..c89675512 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/identity.go @@ -0,0 +1,75 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package tracking // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking" + +import ( + "bytes" + "strconv" + + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil" +) + +type MetricIdentity struct { + Resource pcommon.Resource + InstrumentationLibrary pcommon.InstrumentationScope + MetricType pmetric.MetricType + MetricIsMonotonic bool + MetricName string + MetricUnit string + StartTimestamp pcommon.Timestamp + Attributes pcommon.Map + MetricValueType pmetric.NumberDataPointValueType +} + +const ( + A = int32('A') + SEP = byte(0x1E) + SEPSTR = string(SEP) +) + +func (mi *MetricIdentity) Write(b *bytes.Buffer) { + b.WriteRune(A + int32(mi.MetricType)) + b.WriteByte(SEP) + b.WriteRune(A + int32(mi.MetricValueType)) + if mi.Resource.Attributes().Len() > 0 { + b.WriteByte(SEP) + resourceHash := pdatautil.MapHash(mi.Resource.Attributes()) + b.Write(resourceHash[:]) + } + + b.WriteByte(SEP) + b.WriteString(mi.InstrumentationLibrary.Name()) + b.WriteByte(SEP) + b.WriteString(mi.InstrumentationLibrary.Version()) + b.WriteByte(SEP) + if mi.MetricIsMonotonic { + b.WriteByte('Y') + } else { + b.WriteByte('N') + } + + b.WriteByte(SEP) + b.WriteString(mi.MetricName) + b.WriteByte(SEP) + b.WriteString(mi.MetricUnit) + + if mi.Attributes.Len() > 0 { + b.WriteByte(SEP) + attrsHash := pdatautil.MapHash(mi.Attributes) + b.Write(attrsHash[:]) + } + b.WriteByte(SEP) + b.WriteString(strconv.FormatInt(int64(mi.StartTimestamp), 36)) +} + +func (mi *MetricIdentity) IsFloatVal() bool { + return mi.MetricValueType == pmetric.NumberDataPointValueTypeDouble +} + +func (mi *MetricIdentity) IsSupportedMetricType() bool { + return mi.MetricType == pmetric.MetricTypeSum || mi.MetricType == pmetric.MetricTypeHistogram +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/metric.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/metric.go new file mode 100644 index 000000000..3c9c1d582 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/metric.go @@ -0,0 +1,9 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package tracking // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking" + +type MetricPoint struct { + Identity MetricIdentity + Value ValuePoint +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/tracker.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/tracker.go new file mode 100644 index 000000000..21435a14b --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/tracker.go @@ -0,0 +1,245 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package tracking // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking" + +import ( + "bytes" + "context" + "fmt" + "math" + "sync" + "time" + + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.uber.org/zap" +) + +// Allocate a minimum of 64 bytes to the builder initially +const initialBytes = 64 + +type InitialValue int + +const ( + InitialValueAuto InitialValue = iota + InitialValueKeep + InitialValueDrop +) + +func (i *InitialValue) String() string { + switch *i { + case InitialValueAuto: + return "auto" + case InitialValueKeep: + return "keep" + case InitialValueDrop: + return "drop" + } + return "unknown" +} + +func (i *InitialValue) UnmarshalText(text []byte) error { + switch string(text) { + case "auto": + *i = InitialValueAuto + case "keep": + *i = InitialValueKeep + case "drop": + *i = InitialValueDrop + default: + return fmt.Errorf("unknown initial_value: %s", text) + } + return nil +} + +var identityBufferPool = sync.Pool{ + New: func() any { + return bytes.NewBuffer(make([]byte, initialBytes)) + }, +} + +type State struct { + sync.Mutex + PrevPoint ValuePoint +} + +type DeltaValue struct { + StartTimestamp pcommon.Timestamp + FloatValue float64 + IntValue int64 + HistogramValue *HistogramPoint +} + +func NewMetricTracker(ctx context.Context, logger *zap.Logger, maxStaleness time.Duration, initalValue InitialValue) *MetricTracker { + t := &MetricTracker{ + logger: logger, + maxStaleness: maxStaleness, + initialValue: initalValue, + startTime: pcommon.NewTimestampFromTime(time.Now()), + } + if maxStaleness > 0 { + go t.sweeper(ctx, t.removeStale) + } + return t +} + +type MetricTracker struct { + logger *zap.Logger + maxStaleness time.Duration + states sync.Map + initialValue InitialValue + startTime pcommon.Timestamp +} + +func (t *MetricTracker) Convert(in MetricPoint) (out DeltaValue, valid bool) { + metricID := in.Identity + metricPoint := in.Value + if !metricID.IsSupportedMetricType() { + return + } + + // NaN is used to signal "stale" metrics. + // These are ignored for now. + // https://github.com/open-telemetry/opentelemetry-collector/pull/3423 + if metricID.IsFloatVal() && math.IsNaN(metricPoint.FloatValue) { + return + } + + b := identityBufferPool.Get().(*bytes.Buffer) + b.Reset() + metricID.Write(b) + hashableID := b.String() + identityBufferPool.Put(b) + + s, ok := t.states.LoadOrStore(hashableID, &State{ + PrevPoint: metricPoint, + }) + if !ok { + switch metricID.MetricType { + case pmetric.MetricTypeHistogram: + val := metricPoint.HistogramValue.Clone() + out.HistogramValue = &val + case pmetric.MetricTypeSum: + out.IntValue = metricPoint.IntValue + out.FloatValue = metricPoint.FloatValue + case pmetric.MetricTypeEmpty, pmetric.MetricTypeGauge, pmetric.MetricTypeExponentialHistogram, pmetric.MetricTypeSummary: + } + switch t.initialValue { + case InitialValueAuto: + if metricID.StartTimestamp < t.startTime || metricPoint.ObservedTimestamp == metricID.StartTimestamp { + return + } + out.StartTimestamp = metricID.StartTimestamp + valid = true + case InitialValueKeep: + valid = true + case InitialValueDrop: + } + return + } + + valid = true + + state := s.(*State) + state.Lock() + defer state.Unlock() + + out.StartTimestamp = state.PrevPoint.ObservedTimestamp + + switch metricID.MetricType { + case pmetric.MetricTypeHistogram: + value := metricPoint.HistogramValue + prevValue := state.PrevPoint.HistogramValue + if math.IsNaN(value.Sum) { + value.Sum = prevValue.Sum + } + + if len(value.Buckets) != len(prevValue.Buckets) { + valid = false + } + + delta := value.Clone() + + // Calculate deltas unless histogram count was reset + if valid && delta.Count >= prevValue.Count { + delta.Count -= prevValue.Count + delta.Sum -= prevValue.Sum + for index, prevBucket := range prevValue.Buckets { + delta.Buckets[index] -= prevBucket + } + } + + out.HistogramValue = &delta + case pmetric.MetricTypeSum: + if metricID.IsFloatVal() { + value := metricPoint.FloatValue + prevValue := state.PrevPoint.FloatValue + delta := value - prevValue + + // Detect reset (non-monotonic sums are not converted) + if value < prevValue { + valid = false + } + + out.FloatValue = delta + } else { + value := metricPoint.IntValue + prevValue := state.PrevPoint.IntValue + delta := value - prevValue + + // Detect reset (non-monotonic sums are not converted) + if value < prevValue { + valid = false + } + + out.IntValue = delta + } + case pmetric.MetricTypeEmpty, pmetric.MetricTypeGauge, pmetric.MetricTypeExponentialHistogram, pmetric.MetricTypeSummary: + } + + state.PrevPoint = metricPoint + return +} + +func (t *MetricTracker) removeStale(staleBefore pcommon.Timestamp) { + t.states.Range(func(key, value any) bool { + s := value.(*State) + + // There is a known race condition here. + // Because the state may be in the process of updating at the + // same time as the stale removal, there is a chance that we + // will remove a "stale" state that is in the process of + // updating. This can only happen when datapoints arrive around + // the expiration time. + // + // In this case, the possible outcomes are: + // * Updating goroutine wins, point will not be stale + // * Stale removal wins, updating goroutine will still see + // the removed state but the state after the update will + // not be persisted. The next update will load an entirely + // new state. + s.Lock() + lastObserved := s.PrevPoint.ObservedTimestamp + s.Unlock() + if lastObserved < staleBefore { + t.logger.Debug("removing stale state key", zap.String("key", key.(string))) + t.states.Delete(key) + } + return true + }) +} + +func (t *MetricTracker) sweeper(ctx context.Context, remove func(pcommon.Timestamp)) { + ticker := time.NewTicker(t.maxStaleness) + for { + select { + case currentTime := <-ticker.C: + staleBefore := pcommon.NewTimestampFromTime(currentTime.Add(-t.maxStaleness)) + remove(staleBefore) + case <-ctx.Done(): + ticker.Stop() + return + } + } +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/value.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/value.go new file mode 100644 index 000000000..64d19fe39 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking/value.go @@ -0,0 +1,30 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package tracking // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking" + +import "go.opentelemetry.io/collector/pdata/pcommon" + +type ValuePoint struct { + ObservedTimestamp pcommon.Timestamp + FloatValue float64 + IntValue int64 + HistogramValue *HistogramPoint +} + +type HistogramPoint struct { + Count uint64 + Sum float64 + Buckets []uint64 +} + +func (point *HistogramPoint) Clone() HistogramPoint { + bucketValues := make([]uint64, len(point.Buckets)) + copy(bucketValues, point.Buckets) + + return HistogramPoint{ + Count: point.Count, + Sum: point.Sum, + Buckets: bucketValues, + } +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/metadata.yaml b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/metadata.yaml new file mode 100644 index 000000000..070a6ecc0 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/metadata.yaml @@ -0,0 +1,12 @@ +type: cumulativetodelta + +status: + class: processor + stability: + beta: [metrics] + distributions: [contrib, k8s] + warnings: [Statefulness] + codeowners: + active: [TylerHelmuth] +tests: + config: diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/processor.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/processor.go new file mode 100644 index 000000000..0c7673a9a --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/processor.go @@ -0,0 +1,202 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package cumulativetodeltaprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor" + +import ( + "context" + "math" + + "go.opentelemetry.io/collector/pdata/pmetric" + "go.uber.org/zap" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterset" + "github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking" +) + +type cumulativeToDeltaProcessor struct { + includeFS filterset.FilterSet + excludeFS filterset.FilterSet + logger *zap.Logger + deltaCalculator *tracking.MetricTracker + cancelFunc context.CancelFunc +} + +func newCumulativeToDeltaProcessor(config *Config, logger *zap.Logger) *cumulativeToDeltaProcessor { + ctx, cancel := context.WithCancel(context.Background()) + p := &cumulativeToDeltaProcessor{ + logger: logger, + deltaCalculator: tracking.NewMetricTracker(ctx, logger, config.MaxStaleness, config.InitialValue), + cancelFunc: cancel, + } + if len(config.Include.Metrics) > 0 { + p.includeFS, _ = filterset.CreateFilterSet(config.Include.Metrics, &config.Include.Config) + } + if len(config.Exclude.Metrics) > 0 { + p.excludeFS, _ = filterset.CreateFilterSet(config.Exclude.Metrics, &config.Exclude.Config) + } + return p +} + +// processMetrics implements the ProcessMetricsFunc type. +func (ctdp *cumulativeToDeltaProcessor) processMetrics(_ context.Context, md pmetric.Metrics) (pmetric.Metrics, error) { + md.ResourceMetrics().RemoveIf(func(rm pmetric.ResourceMetrics) bool { + rm.ScopeMetrics().RemoveIf(func(ilm pmetric.ScopeMetrics) bool { + ilm.Metrics().RemoveIf(func(m pmetric.Metric) bool { + if !ctdp.shouldConvertMetric(m.Name()) { + return false + } + switch m.Type() { + case pmetric.MetricTypeSum: + ms := m.Sum() + if ms.AggregationTemporality() != pmetric.AggregationTemporalityCumulative { + return false + } + + // Ignore any metrics that aren't monotonic + if !ms.IsMonotonic() { + return false + } + + baseIdentity := tracking.MetricIdentity{ + Resource: rm.Resource(), + InstrumentationLibrary: ilm.Scope(), + MetricType: m.Type(), + MetricName: m.Name(), + MetricUnit: m.Unit(), + MetricIsMonotonic: ms.IsMonotonic(), + } + ctdp.convertNumberDataPoints(ms.DataPoints(), baseIdentity) + ms.SetAggregationTemporality(pmetric.AggregationTemporalityDelta) + return ms.DataPoints().Len() == 0 + case pmetric.MetricTypeHistogram: + ms := m.Histogram() + if ms.AggregationTemporality() != pmetric.AggregationTemporalityCumulative { + return false + } + + if ms.DataPoints().Len() == 0 { + return false + } + + baseIdentity := tracking.MetricIdentity{ + Resource: rm.Resource(), + InstrumentationLibrary: ilm.Scope(), + MetricType: m.Type(), + MetricName: m.Name(), + MetricUnit: m.Unit(), + MetricIsMonotonic: true, + MetricValueType: pmetric.NumberDataPointValueTypeInt, + } + + ctdp.convertHistogramDataPoints(ms.DataPoints(), baseIdentity) + + ms.SetAggregationTemporality(pmetric.AggregationTemporalityDelta) + return ms.DataPoints().Len() == 0 + case pmetric.MetricTypeEmpty, pmetric.MetricTypeGauge, pmetric.MetricTypeExponentialHistogram, pmetric.MetricTypeSummary: + fallthrough + default: + return false + } + }) + return ilm.Metrics().Len() == 0 + }) + return rm.ScopeMetrics().Len() == 0 + }) + return md, nil +} + +func (ctdp *cumulativeToDeltaProcessor) shutdown(context.Context) error { + ctdp.cancelFunc() + return nil +} + +func (ctdp *cumulativeToDeltaProcessor) shouldConvertMetric(metricName string) bool { + return (ctdp.includeFS == nil || ctdp.includeFS.Matches(metricName)) && + (ctdp.excludeFS == nil || !ctdp.excludeFS.Matches(metricName)) +} + +func (ctdp *cumulativeToDeltaProcessor) convertNumberDataPoints(dps pmetric.NumberDataPointSlice, baseIdentity tracking.MetricIdentity) { + dps.RemoveIf(func(dp pmetric.NumberDataPoint) bool { + id := baseIdentity + id.StartTimestamp = dp.StartTimestamp() + id.Attributes = dp.Attributes() + id.MetricValueType = dp.ValueType() + point := tracking.ValuePoint{ + ObservedTimestamp: dp.Timestamp(), + } + + if dp.Flags().NoRecordedValue() { + // drop points with no value + return true + } + if id.IsFloatVal() { + // Do not attempt to transform NaN values + if math.IsNaN(dp.DoubleValue()) { + return false + } + point.FloatValue = dp.DoubleValue() + } else { + point.IntValue = dp.IntValue() + } + trackingPoint := tracking.MetricPoint{ + Identity: id, + Value: point, + } + delta, valid := ctdp.deltaCalculator.Convert(trackingPoint) + if !valid { + return true + } + dp.SetStartTimestamp(delta.StartTimestamp) + if id.IsFloatVal() { + dp.SetDoubleValue(delta.FloatValue) + } else { + dp.SetIntValue(delta.IntValue) + } + return false + }) +} + +func (ctdp *cumulativeToDeltaProcessor) convertHistogramDataPoints(in any, baseIdentity tracking.MetricIdentity) { + if dps, ok := in.(pmetric.HistogramDataPointSlice); ok { + dps.RemoveIf(func(dp pmetric.HistogramDataPoint) bool { + id := baseIdentity + id.StartTimestamp = dp.StartTimestamp() + id.Attributes = dp.Attributes() + + if dp.Flags().NoRecordedValue() { + // drop points with no value + return true + } + + point := tracking.ValuePoint{ + ObservedTimestamp: dp.Timestamp(), + HistogramValue: &tracking.HistogramPoint{ + Count: dp.Count(), + Sum: dp.Sum(), + Buckets: dp.BucketCounts().AsRaw(), + }, + } + + trackingPoint := tracking.MetricPoint{ + Identity: id, + Value: point, + } + delta, valid := ctdp.deltaCalculator.Convert(trackingPoint) + + if valid { + dp.SetStartTimestamp(delta.StartTimestamp) + dp.SetCount(delta.HistogramValue.Count) + if dp.HasSum() && !math.IsNaN(dp.Sum()) { + dp.SetSum(delta.HistogramValue.Sum) + } + dp.BucketCounts().FromRaw(delta.HistogramValue.Buckets) + dp.RemoveMin() + dp.RemoveMax() + return false + } + + return !valid + }) + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 86815d603..1c00cbb74 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1054,6 +1054,11 @@ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/winperfcounters/in ## explicit; go 1.22.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor/internal/metadata +# github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor v0.118.0 +## explicit; go 1.22.0 +github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor +github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/metadata +github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor/internal/tracking # github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.118.0 ## explicit; go 1.22.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor From 815511d4f3e5843a9968d377f216dfb9e9dcce49 Mon Sep 17 00:00:00 2001 From: Alex Lew Date: Fri, 21 Feb 2025 14:48:02 -0800 Subject: [PATCH 2/3] feat: add pprof extension --- builder-config.yaml | 1 + go.mod | 1 + observecol/components.go | 3 + observecol/go.mod | 1 + .../extension/pprofextension/LICENSE | 201 ++++++++++++++++++ .../extension/pprofextension/Makefile | 1 + .../extension/pprofextension/README.md | 103 +++++++++ .../extension/pprofextension/config.go | 38 ++++ .../extension/pprofextension/doc.go | 8 + .../extension/pprofextension/factory.go | 46 ++++ .../internal/metadata/generated_status.go | 16 ++ .../extension/pprofextension/metadata.yaml | 12 ++ .../pprofextension/pprofextension.go | 106 +++++++++ vendor/modules.txt | 4 + 14 files changed, 541 insertions(+) create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/LICENSE create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/Makefile create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/README.md create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/config.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/doc.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/factory.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/internal/metadata/generated_status.go create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/metadata.yaml create mode 100644 vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/pprofextension.go diff --git a/builder-config.yaml b/builder-config.yaml index 32d8a82db..2c8949cb6 100644 --- a/builder-config.yaml +++ b/builder-config.yaml @@ -63,6 +63,7 @@ extensions: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.118.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage v0.118.0 + - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension v0.118.0 connectors: - gomod: go.opentelemetry.io/collector/connector/forwardconnector v0.118.0 diff --git a/go.mod b/go.mod index 4d7789ba7..d953e4853 100644 --- a/go.mod +++ b/go.mod @@ -177,6 +177,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusremotewriteexporter v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.118.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/ecsutil v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.118.0 // indirect diff --git a/observecol/components.go b/observecol/components.go index 642b3a08b..d4ee9c012 100644 --- a/observecol/components.go +++ b/observecol/components.go @@ -19,6 +19,7 @@ import ( zpagesextension "go.opentelemetry.io/collector/extension/zpagesextension" healthcheckextension "github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension" filestorage "github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage" + pprofextension "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension" batchprocessor "go.opentelemetry.io/collector/processor/batchprocessor" memorylimiterprocessor "go.opentelemetry.io/collector/processor/memorylimiterprocessor" attributesprocessor "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor" @@ -67,6 +68,7 @@ func components() (otelcol.Factories, error) { zpagesextension.NewFactory(), healthcheckextension.NewFactory(), filestorage.NewFactory(), + pprofextension.NewFactory(), ) if err != nil { return otelcol.Factories{}, err @@ -75,6 +77,7 @@ func components() (otelcol.Factories, error) { factories.ExtensionModules[zpagesextension.NewFactory().Type()] = "go.opentelemetry.io/collector/extension/zpagesextension v0.118.0" factories.ExtensionModules[healthcheckextension.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.118.0" factories.ExtensionModules[filestorage.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage v0.118.0" + factories.ExtensionModules[pprofextension.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension v0.118.0" factories.Receivers, err = receiver.MakeFactoryMap( otlpreceiver.NewFactory(), diff --git a/observecol/go.mod b/observecol/go.mod index 0c7810ffe..7d9a02435 100644 --- a/observecol/go.mod +++ b/observecol/go.mod @@ -11,6 +11,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusremotewriteexporter v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.118.0 + github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor v0.118.0 diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/LICENSE b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/Makefile b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/Makefile new file mode 100644 index 000000000..ded7a3609 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/README.md b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/README.md new file mode 100644 index 000000000..21225dd40 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/README.md @@ -0,0 +1,103 @@ +# Performance Profiler + + +| Status | | +| ------------- |-----------| +| Stability | [beta] | +| Distributions | [core], [contrib], [k8s] | +| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Fpprof%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Fpprof) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Fpprof%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Fpprof) | +| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@MovieStoreGuy](https://www.github.com/MovieStoreGuy) | + +[beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta +[core]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol +[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib +[k8s]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-k8s + + +Performance Profiler extension enables the golang `net/http/pprof` endpoint. +This is typically used by developers to collect performance profiles and +investigate issues with the service. + +The following settings are required: + +- `endpoint` (default = localhost:1777): The endpoint in which the pprof will +be listening to. Use localhost: to make it available only locally, or +":" to make it available on all network interfaces. +- `block_profile_fraction` (default = 0): Fraction of blocking events that +are profiled. A value <= 0 disables profiling. See +https://golang.org/pkg/runtime/#SetBlockProfileRate for details. +- `mutex_profile_fraction` (default = 0): Fraction of mutex contention +events that are profiled. A value <= 0 disables profiling. See +https://golang.org/pkg/runtime/#SetMutexProfileFraction for details. + +The following settings can be optionally configured: + +- `save_to_file`: File name to save the CPU profile to. The profiling starts when the +Collector starts and is saved to the file when the Collector is terminated. + +Example: +```yaml + +extensions: + pprof: +``` + +The full list of settings exposed for this exporter are documented [here](./config.go) +with detailed sample configurations [here](./testdata/config.yaml). + + +### Go Profiling with pprof basics + +The profiler can be used to improve a program. +The most common usage is a CPU profile, which determines where the program spends the most time while actively consuming resources. +After generating a profile, we can interpret it in different ways. +Go's _pprof_ offers a text, visualization, or web-based analysis. +To collect a meaningful profile, it should run on an idle machine and if that is not possible, it is best to generate the profile several times to get consistent results. + +The profiler stops the program multiple times per second and collects information (such as program counters) at that point in time. +This is called a sample, and a profile is a collection of those samples. + +#### Generating a profile +The extension enables the collection of profiling data expected by _pprof_. +To generate a profile, include the extension in your program and run it to start the server. +If you are using the default config, it will listen on `localhost:1777`. +To save a CPU profile on your machine, run `go tool pprof http://localhost:1777/debug/pprof/profile\?seconds\=30`. +This will enter the interactive mode of _pprof_, where you can analyze the profile. + +There are different endpoints for other types of profiles. +For instance, the memory can be analyzed using `go tool pprof http://localhost:1777/debug/pprof/heap`. +To see all available profiles, visit `http://localhost:1777/debug/pprof/` in your browser. + +#### Analyzing a profile + +After running the above command to save the profile, _pprof_ will enter the interactive mode. +From here, the profiles can be analyzed. + +Use the command `web` to open an image of the complete call graph in your browser. +Each box corresponds to a function in the program, and it is sized according to the number of samples in which this function was running. +This means, if the box of a function is bigger, it was executed more often than a function in a smaller box. +The arrows between boxes show the connectivity of the functions. +If there is an arrow from box A to B, A called B. +The numbers along the edges represent how often that call happened. +This includes every call of a recursive function. +The color of the edges also represents that number. +A red edge means more resources were used, whereas grey indicates the used resources were close to zero. + +However, the complete call graph can be a bit noisy. +A good place to start breaking it down is using the `topN` command. +It will show you the top `N` nodes, consuming the most resources. +The output is a table, where the first two columns show the number and percentage of total samples where the function was running (`flat`). +The third column shows the total percentage, for instance stating that function X was running in 20% of the samples. +The two remaining columns show the cumulative (`cum`) numbers of the profile. + +From here, the results can be filtered. +Choose one of the top consuming functions which you would like to analyze. +_pprof_ uses a regex-based search to filter for functions matching the input. +Type `web ` to show the call graph for this specific function. +The image in your browser should now be more clear and less cluttered. + +The `list` command is also useful. +Type `list ` to see the source code of your function, annotated with the resource consumption (`flat` and `cum` columns like in the `topN` command). +If you prefer to view it in your browser, use the `weblist ` command instead. +In this view, you can see which line exactly used the most resources and start to improve it. + diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/config.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/config.go new file mode 100644 index 000000000..0ab9149c6 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/config.go @@ -0,0 +1,38 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package pprofextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension" + +import ( + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confignet" +) + +// Config has the configuration for the extension enabling the golang +// net/http/pprof (Performance Profiler) extension. +type Config struct { + // TCPAddr is the address and port in which the pprof will be listening to. + // Use localhost: to make it available only locally, or ":" to + // make it available on all network interfaces. + TCPAddr confignet.TCPAddrConfig `mapstructure:",squash"` + + // Fraction of blocking events that are profiled. A value <= 0 disables + // profiling. See https://golang.org/pkg/runtime/#SetBlockProfileRate for details. + BlockProfileFraction int `mapstructure:"block_profile_fraction"` + + // Fraction of mutex contention events that are profiled. A value <= 0 + // disables profiling. See https://golang.org/pkg/runtime/#SetMutexProfileFraction + // for details. + MutexProfileFraction int `mapstructure:"mutex_profile_fraction"` + + // Optional file name to save the CPU profile to. The profiling starts when the + // Collector starts and is saved to the file when the Collector is terminated. + SaveToFile string `mapstructure:"save_to_file"` +} + +var _ component.Config = (*Config)(nil) + +// Validate checks if the extension configuration is valid +func (cfg *Config) Validate() error { + return nil +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/doc.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/doc.go new file mode 100644 index 000000000..d1b13c950 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/doc.go @@ -0,0 +1,8 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:generate mdatagen metadata.yaml + +// Package pprofextension implements an extension that exposes the golang +// net/http/pprof (Performance Profiler) in a HTTP endpoint. +package pprofextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension" diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/factory.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/factory.go new file mode 100644 index 000000000..78b5d7a10 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/factory.go @@ -0,0 +1,46 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package pprofextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension" + +import ( + "context" + "errors" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confignet" + "go.opentelemetry.io/collector/extension" + + "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/internal/metadata" +) + +const ( + defaultEndpoint = "localhost:1777" +) + +// NewFactory creates a factory for pprof extension. +func NewFactory() extension.Factory { + return extension.NewFactory( + metadata.Type, + createDefaultConfig, + createExtension, + metadata.ExtensionStability, + ) +} + +func createDefaultConfig() component.Config { + return &Config{ + TCPAddr: confignet.TCPAddrConfig{ + Endpoint: defaultEndpoint, + }, + } +} + +func createExtension(_ context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) { + config := cfg.(*Config) + if config.TCPAddr.Endpoint == "" { + return nil, errors.New("\"endpoint\" is required when using the \"pprof\" extension") + } + + return newServer(*config, set.TelemetrySettings), nil +} diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/internal/metadata/generated_status.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/internal/metadata/generated_status.go new file mode 100644 index 000000000..a98c35bc4 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/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("pprof") + ScopeName = "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension" +) + +const ( + ExtensionStability = component.StabilityLevelBeta +) diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/metadata.yaml b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/metadata.yaml new file mode 100644 index 000000000..e5a2e11bb --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/metadata.yaml @@ -0,0 +1,12 @@ +type: pprof + +status: + class: extension + stability: + beta: [extension] + distributions: [core, contrib, k8s] + codeowners: + active: [MovieStoreGuy] + +tests: + config: diff --git a/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/pprofextension.go b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/pprofextension.go new file mode 100644 index 000000000..830305b49 --- /dev/null +++ b/vendor/github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/pprofextension.go @@ -0,0 +1,106 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package pprofextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension" + +import ( + "context" + "errors" + "net" + "net/http" + _ "net/http/pprof" // #nosec Needed to enable the performance profiler + "os" + "runtime" + "runtime/pprof" + "sync/atomic" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componentstatus" + "go.uber.org/zap" +) + +var running = &atomic.Bool{} + +type pprofExtension struct { + config Config + file *os.File + server http.Server + stopCh chan struct{} + telemetrySettings component.TelemetrySettings +} + +func (p *pprofExtension) Start(_ context.Context, host component.Host) error { + // The runtime settings are global to the application, so while in principle it + // is possible to have more than one instance, running multiple will mean that + // the settings of the last started instance will prevail. In order to avoid + // this issue we will allow the start of a single instance once per process + // Summary: only a single instance can be running in the same process. + if !running.CompareAndSwap(false, true) { + return errors.New("only a single pprof extension instance can be running per process") + } + + // Take care that if any error happen when starting the active instance is cleaned. + var startErr error + defer func() { + if startErr != nil { + running.Store(false) + } + }() + + // Start the listener here so we can have earlier failure if port is + // already in use. + var ln net.Listener + ln, startErr = p.config.TCPAddr.Listen(context.Background()) + if startErr != nil { + return startErr + } + + runtime.SetBlockProfileRate(p.config.BlockProfileFraction) + runtime.SetMutexProfileFraction(p.config.MutexProfileFraction) + + p.telemetrySettings.Logger.Info("Starting net/http/pprof server", zap.Any("config", p.config)) + p.stopCh = make(chan struct{}) + go func() { + defer func() { + running.Store(false) + close(p.stopCh) + }() + + // The listener ownership goes to the server. + if errHTTP := p.server.Serve(ln); !errors.Is(errHTTP, http.ErrServerClosed) && errHTTP != nil { + componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errHTTP)) + } + }() + + if p.config.SaveToFile != "" { + var f *os.File + f, startErr = os.Create(p.config.SaveToFile) + if startErr != nil { + return startErr + } + p.file = f + startErr = pprof.StartCPUProfile(f) + } + + return startErr +} + +func (p *pprofExtension) Shutdown(context.Context) error { + defer running.Store(false) + if p.file != nil { + pprof.StopCPUProfile() + _ = p.file.Close() // ignore the error + } + err := p.server.Close() + if p.stopCh != nil { + <-p.stopCh + } + return err +} + +func newServer(config Config, params component.TelemetrySettings) *pprofExtension { + return &pprofExtension{ + config: config, + telemetrySettings: params, + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1c00cbb74..a6881459d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -864,6 +864,10 @@ github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusrem github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension/internal/healthcheck github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension/internal/metadata +# github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension v0.118.0 +## explicit; go 1.22.0 +github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension +github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension/internal/metadata # github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage v0.118.0 ## explicit; go 1.22.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage From 75eb21284b8c0ee3adbbaa79fe5ef05e689abcd0 Mon Sep 17 00:00:00 2001 From: Alex Lew Date: Mon, 24 Feb 2025 09:26:56 -0800 Subject: [PATCH 3/3] update readme to include pprof extension --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bfd2c4cd4..428e77a77 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ This section lists the components that are included in the Observe Distribution |----------------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------|--------------------------------------|-----------------------------| | [awsecscontainermetrics][awsecscontainermetricsreceiver] | [attributes][attributesprocessor] | [debug][debugexporter] | [file_storage][filestorage] | [count][countconnector] | | [docker_stats][dockerstatsreceiver] | [batch][batchprocessor] | [file][fileexporter] | [health_check][healthcheckextension] | [forward][forwardconnector] | -| [elasticsearch][elasticsearchreceiver] | [cumulativetodelta][cumulativetodeltaprocessor] | [otlphttp][otlphttpexporter] | [zpages][zpagesextension] | | -| [filelog][filelogreceiver] | [deltatocumulative][deltatocumulativeprocessor] | [prometheusremotewrite][prometheusremotewriteexporter] | | | +| [elasticsearch][elasticsearchreceiver] | [cumulativetodelta][cumulativetodeltaprocessor] | [otlphttp][otlphttpexporter] | [pprof][pprofextension] | | +| [filelog][filelogreceiver] | [deltatocumulative][deltatocumulativeprocessor] | [prometheusremotewrite][prometheusremotewriteexporter] | [zpages][zpagesextension] | | | [filestats][filestatsreceiver] | [filter][filterprocessor] | | | | | [hostmetrics][hostmetricsreceiver] | [k8sattributes][k8sattributesprocessor] | | | | | [httpcheck][httpcheckreceiver] | [memory_limiter][memorylimiterprocessor] | | | | @@ -138,4 +138,5 @@ This section lists the components that are included in the Observe Distribution [forwardconnector]: https://github.com/open-telemetry/opentelemetry-collector/tree/v0.118.0/connector/forwardconnector [filestorage]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/extension/storage/filestorage [healthcheckextension]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/extension/healthcheckextension +[pprofextension]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.118.0/extension/pprofextension [zpagesextension]: https://github.com/open-telemetry/opentelemetry-collector/tree/v0.118.0/extension/zpagesextension